mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge branch 'master' of github.com:YosysHQ/yosys into clifford/fix968
This commit is contained in:
		
						commit
						d187be39d6
					
				
					 35 changed files with 788 additions and 291 deletions
				
			
		|  | @ -163,31 +163,61 @@ struct FirrtlWorker | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
| 	/* Memories defined within this module. */ | 	/* Memories defined within this module. */ | ||||||
| 	 struct memory { | 	struct memory { | ||||||
| 		 string name;					// memory name
 | 		Cell *pCell;					// for error reporting
 | ||||||
| 		 int abits;						// number of address bits
 | 		string name;					// memory name
 | ||||||
| 		 int size;						// size (in units) of the memory
 | 		int abits;						// number of address bits
 | ||||||
| 		 int width;						// size (in bits) of each element
 | 		int size;						// size (in units) of the memory
 | ||||||
| 		 int read_latency; | 		int width;						// size (in bits) of each element
 | ||||||
| 		 int write_latency; | 		int read_latency; | ||||||
| 		 vector<read_port> read_ports; | 		int write_latency; | ||||||
| 		 vector<write_port> write_ports; | 		vector<read_port> read_ports; | ||||||
| 		 std::string init_file; | 		vector<write_port> write_ports; | ||||||
| 		 std::string init_file_srcFileSpec; | 		std::string init_file; | ||||||
| 		 memory(string name, int abits, int size, int width) : name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {} | 		std::string init_file_srcFileSpec; | ||||||
| 		 memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} | 		string srcLine; | ||||||
| 		 void add_memory_read_port(read_port &rp) { | 		memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") { | ||||||
| 			 read_ports.push_back(rp); | 			// Provide defaults for abits or size if one (but not the other) is specified.
 | ||||||
| 		 } | 			if (this->abits == 0 && this->size != 0) { | ||||||
| 		 void add_memory_write_port(write_port &wp) { | 				this->abits = ceil_log2(this->size); | ||||||
| 			 write_ports.push_back(wp); | 			} else if (this->abits != 0 && this->size == 0) { | ||||||
| 		 } | 				this->size = 1 << this->abits; | ||||||
| 		 void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { | 			} | ||||||
| 			 this->init_file = init_file; | 			// Sanity-check this construction.
 | ||||||
| 			 this->init_file_srcFileSpec = init_file_srcFileSpec; | 			if (this->name == "") { | ||||||
|  | 				log_error("Nameless memory%s\n", this->atLine()); | ||||||
|  | 			} | ||||||
|  | 			if (this->abits == 0 && this->size == 0) { | ||||||
|  | 				log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine()); | ||||||
|  | 			} | ||||||
|  | 			if (this->width == 0) { | ||||||
|  | 				log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine()); | ||||||
|  | 			} | ||||||
| 		 } | 		 } | ||||||
|  | 		// We need a default constructor for the dict insert.
 | ||||||
|  | 	   memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} | ||||||
| 
 | 
 | ||||||
| 	 }; | 		const char *atLine() { | ||||||
|  | 			if (srcLine == "") { | ||||||
|  | 				if (pCell) { | ||||||
|  | 					auto p = pCell->attributes.find("\\src"); | ||||||
|  | 					srcLine = " at " + p->second.decode_string(); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return srcLine.c_str(); | ||||||
|  | 		} | ||||||
|  | 		void add_memory_read_port(read_port &rp) { | ||||||
|  | 			read_ports.push_back(rp); | ||||||
|  | 		} | ||||||
|  | 		void add_memory_write_port(write_port &wp) { | ||||||
|  | 			write_ports.push_back(wp); | ||||||
|  | 		} | ||||||
|  | 		void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { | ||||||
|  | 			this->init_file = init_file; | ||||||
|  | 			this->init_file_srcFileSpec = init_file_srcFileSpec; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	}; | ||||||
| 	dict<string, memory> memories; | 	dict<string, memory> memories; | ||||||
| 
 | 
 | ||||||
| 	void register_memory(memory &m) | 	void register_memory(memory &m) | ||||||
|  | @ -604,7 +634,7 @@ struct FirrtlWorker | ||||||
| 				int abits = cell->parameters.at("\\ABITS").as_int(); | 				int abits = cell->parameters.at("\\ABITS").as_int(); | ||||||
| 				int width = cell->parameters.at("\\WIDTH").as_int(); | 				int width = cell->parameters.at("\\WIDTH").as_int(); | ||||||
| 				int size = cell->parameters.at("\\SIZE").as_int(); | 				int size = cell->parameters.at("\\SIZE").as_int(); | ||||||
| 				memory m(mem_id, abits, size, width); | 				memory m(cell, mem_id, abits, size, width); | ||||||
| 				int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); | 				int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); | ||||||
| 				int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); | 				int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); | ||||||
| 
 | 
 | ||||||
|  | @ -681,6 +711,8 @@ struct FirrtlWorker | ||||||
| 			{ | 			{ | ||||||
| 				std::string cell_type = fid(cell->type); | 				std::string cell_type = fid(cell->type); | ||||||
| 				std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string()); | 				std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string()); | ||||||
|  | 				int abits = cell->parameters.at("\\ABITS").as_int(); | ||||||
|  | 				int width = cell->parameters.at("\\WIDTH").as_int(); | ||||||
| 				memory *mp = nullptr; | 				memory *mp = nullptr; | ||||||
| 				if (cell->type == "$meminit" ) { | 				if (cell->type == "$meminit" ) { | ||||||
| 					log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str()); | 					log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str()); | ||||||
|  | @ -693,6 +725,11 @@ struct FirrtlWorker | ||||||
| 					Const clk_enable = cell->parameters.at("\\CLK_ENABLE"); | 					Const clk_enable = cell->parameters.at("\\CLK_ENABLE"); | ||||||
| 					Const clk_polarity = cell->parameters.at("\\CLK_POLARITY"); | 					Const clk_polarity = cell->parameters.at("\\CLK_POLARITY"); | ||||||
| 
 | 
 | ||||||
|  | 					// Do we already have an entry for this memory?
 | ||||||
|  | 					if (memories.count(mem_id) == 0) { | ||||||
|  | 						memory m(cell, mem_id, abits, 0, width); | ||||||
|  | 						register_memory(m); | ||||||
|  | 					} | ||||||
| 					mp = &memories.at(mem_id); | 					mp = &memories.at(mem_id); | ||||||
| 					int portNum = 0; | 					int portNum = 0; | ||||||
| 					bool transparency = false; | 					bool transparency = false; | ||||||
|  | @ -890,7 +927,7 @@ struct FirrtlWorker | ||||||
| 
 | 
 | ||||||
| 		// If we have any memory definitions, output them.
 | 		// If we have any memory definitions, output them.
 | ||||||
| 		for (auto kv : memories) { | 		for (auto kv : memories) { | ||||||
| 			memory m = kv.second; | 			memory &m = kv.second; | ||||||
| 			f << stringf("    mem %s:\n", m.name.c_str()); | 			f << stringf("    mem %s:\n", m.name.c_str()); | ||||||
| 			f << stringf("      data-type => UInt<%d>\n", m.width); | 			f << stringf("      data-type => UInt<%d>\n", m.width); | ||||||
| 			f << stringf("      depth => %d\n", m.size); | 			f << stringf("      depth => %d\n", m.size); | ||||||
|  |  | ||||||
|  | @ -645,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun | ||||||
| 			if (!id_ast->children[0]->range_valid) | 			if (!id_ast->children[0]->range_valid) | ||||||
| 				log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); | 				log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); | ||||||
| 			this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; | 			this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; | ||||||
|  | 			if (children.size() > 1) | ||||||
|  | 				range = children[1]; | ||||||
| 		} else | 		} else | ||||||
| 			log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str()); | 			log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str()); | ||||||
| 		if (range) { | 		if (range) { | ||||||
|  |  | ||||||
|  | @ -1605,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:; | ||||||
| 			current_scope[wire_tmp->str] = wire_tmp; | 			current_scope[wire_tmp->str] = wire_tmp; | ||||||
| 			wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | 			wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | ||||||
| 			while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { } | 			while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { } | ||||||
|  | 			wire_tmp->is_logic = true; | ||||||
| 
 | 
 | ||||||
| 			AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); | 			AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); | ||||||
| 			wire_tmp_id->str = wire_tmp->str; | 			wire_tmp_id->str = wire_tmp->str; | ||||||
|  |  | ||||||
|  | @ -45,7 +45,7 @@ YOSYS_NAMESPACE_END | ||||||
| USING_YOSYS_NAMESPACE | USING_YOSYS_NAMESPACE | ||||||
| %} | %} | ||||||
| 
 | 
 | ||||||
| %name-prefix "rtlil_frontend_ilang_yy" | %define api.prefix {rtlil_frontend_ilang_yy} | ||||||
| 
 | 
 | ||||||
| %union { | %union { | ||||||
| 	char *string; | 	char *string; | ||||||
|  |  | ||||||
|  | @ -206,7 +206,9 @@ YOSYS_NAMESPACE_END | ||||||
| "const"      { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } | "const"      { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } | ||||||
| "checker"    { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } | "checker"    { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } | ||||||
| "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } | "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } | ||||||
|  | "final"      { SV_KEYWORD(TOK_FINAL); } | ||||||
| "logic"      { SV_KEYWORD(TOK_LOGIC); } | "logic"      { SV_KEYWORD(TOK_LOGIC); } | ||||||
|  | "var"        { SV_KEYWORD(TOK_VAR); } | ||||||
| "bit"        { SV_KEYWORD(TOK_REG); } | "bit"        { SV_KEYWORD(TOK_REG); } | ||||||
| 
 | 
 | ||||||
| "eventually"   { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } | "eventually"   { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } | ||||||
|  |  | ||||||
|  | @ -96,7 +96,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) | ||||||
| 
 | 
 | ||||||
| %} | %} | ||||||
| 
 | 
 | ||||||
| %name-prefix "frontend_verilog_yy" | %define api.prefix {frontend_verilog_yy} | ||||||
| 
 | 
 | ||||||
| %union { | %union { | ||||||
| 	std::string *string; | 	std::string *string; | ||||||
|  | @ -106,11 +106,11 @@ static void free_attr(std::map<std::string, AstNode*> *al) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL | %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL | ||||||
| %token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER | %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 | ||||||
| %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP | %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP | ||||||
| %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT | %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR | ||||||
| %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC | %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC | ||||||
| %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL | %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL | ||||||
| %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT | %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT | ||||||
|  | @ -456,6 +456,9 @@ wire_type_token: | ||||||
| 	TOK_LOGIC { | 	TOK_LOGIC { | ||||||
| 		astbuf3->is_logic = true; | 		astbuf3->is_logic = true; | ||||||
| 	} | | 	} | | ||||||
|  | 	TOK_VAR { | ||||||
|  | 		astbuf3->is_logic = true; | ||||||
|  | 	} | | ||||||
| 	TOK_INTEGER { | 	TOK_INTEGER { | ||||||
| 		astbuf3->is_reg = true; | 		astbuf3->is_reg = true; | ||||||
| 		astbuf3->range_left = 31; | 		astbuf3->range_left = 31; | ||||||
|  | @ -1341,6 +1344,9 @@ opt_property: | ||||||
| 	TOK_PROPERTY { | 	TOK_PROPERTY { | ||||||
| 		$$ = true; | 		$$ = true; | ||||||
| 	} | | 	} | | ||||||
|  | 	TOK_FINAL { | ||||||
|  | 		$$ = false; | ||||||
|  | 	} | | ||||||
| 	/* empty */ { | 	/* empty */ { | ||||||
| 		$$ = false; | 		$$ = false; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | @ -291,7 +291,7 @@ struct QwpWorker | ||||||
| 		// gaussian elimination
 | 		// gaussian elimination
 | ||||||
| 		for (int i = 0; i < N; i++) | 		for (int i = 0; i < N; i++) | ||||||
| 		{ | 		{ | ||||||
| 			if (config.verbose && ((i+1) % (N/15)) == 0) | 			if (config.verbose && N > 15 && ((i+1) % (N/15)) == 0) | ||||||
| 				log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N); | 				log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N); | ||||||
| 
 | 
 | ||||||
| 			// find best row
 | 			// find best row
 | ||||||
|  |  | ||||||
|  | @ -272,6 +272,10 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	SigPool raw_used_signals_noaliases; | ||||||
|  | 	for (auto &it : module->connections_) | ||||||
|  | 		raw_used_signals_noaliases.add(it.second); | ||||||
|  | 
 | ||||||
| 	module->connections_.clear(); | 	module->connections_.clear(); | ||||||
| 
 | 
 | ||||||
| 	SigPool used_signals; | 	SigPool used_signals; | ||||||
|  | @ -281,6 +285,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos | ||||||
| 		for (auto &it2 : cell->connections_) { | 		for (auto &it2 : cell->connections_) { | ||||||
| 			assign_map.apply(it2.second); | 			assign_map.apply(it2.second); | ||||||
| 			used_signals.add(it2.second); | 			used_signals.add(it2.second); | ||||||
|  | 			raw_used_signals_noaliases.add(it2.second); | ||||||
| 			if (!ct_all.cell_output(cell->type, it2.first)) | 			if (!ct_all.cell_output(cell->type, it2.first)) | ||||||
| 				used_signals_nodrivers.add(it2.second); | 				used_signals_nodrivers.add(it2.second); | ||||||
| 		} | 		} | ||||||
|  | @ -301,53 +306,63 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	std::vector<RTLIL::Wire*> maybe_del_wires; | 	pool<RTLIL::Wire*> del_wires_queue; | ||||||
| 	for (auto wire : module->wires()) | 	for (auto wire : module->wires()) | ||||||
| 	{ | 	{ | ||||||
| 		if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) { | 		SigSpec s1 = SigSpec(wire), s2 = assign_map(s1); | ||||||
| 			RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1; | 		log_assert(GetSize(s1) == GetSize(s2)); | ||||||
| 			assign_map.apply(s2); | 
 | ||||||
| 			if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) { | 		Const initval; | ||||||
| 				maybe_del_wires.push_back(wire); | 		if (wire->attributes.count("\\init")) | ||||||
| 			} else { | 			initval = wire->attributes.at("\\init"); | ||||||
| 				log_assert(GetSize(s1) == GetSize(s2)); | 		if (GetSize(initval) != GetSize(wire)) | ||||||
| 				Const initval; | 			initval.bits.resize(GetSize(wire), State::Sx); | ||||||
| 				if (wire->attributes.count("\\init")) | 		if (initval.is_fully_undef()) | ||||||
| 					initval = wire->attributes.at("\\init"); | 			wire->attributes.erase("\\init"); | ||||||
| 				if (GetSize(initval) != GetSize(wire)) | 
 | ||||||
| 					initval.bits.resize(GetSize(wire), State::Sx); | 		bool delete_this_wire = false; | ||||||
| 				RTLIL::SigSig new_conn; | 		if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) { | ||||||
| 				for (int i = 0; i < GetSize(s1); i++) | 			/* do not delete anything with "keep" or module ports or initialized wires */ | ||||||
| 					if (s1[i] != s2[i]) { | 		} else | ||||||
| 						if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) { | 		if (!purge_mode && check_public_name(wire->name)) { | ||||||
| 							s2[i] = initval[i]; | 			/* do not get rid of public names unless in purge mode */ | ||||||
| 							initval[i] = State::Sx; |  | ||||||
| 						} |  | ||||||
| 						new_conn.first.append_bit(s1[i]); |  | ||||||
| 						new_conn.second.append_bit(s2[i]); |  | ||||||
| 					} |  | ||||||
| 				if (new_conn.first.size() > 0) { |  | ||||||
| 					if (initval.is_fully_undef()) |  | ||||||
| 						wire->attributes.erase("\\init"); |  | ||||||
| 					else |  | ||||||
| 						wire->attributes.at("\\init") = initval; |  | ||||||
| 					used_signals.add(new_conn.first); |  | ||||||
| 					used_signals.add(new_conn.second); |  | ||||||
| 					module->connect(new_conn); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} else { | 		} else { | ||||||
| 			if (!used_signals.check_any(RTLIL::SigSpec(wire))) | 			if (!raw_used_signals_noaliases.check_any(s1)) | ||||||
| 				maybe_del_wires.push_back(wire); | 				delete_this_wire = true; | ||||||
|  | 			if (!used_signals_nodrivers.check_any(s2)) | ||||||
|  | 				delete_this_wire = true; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire)); | 		if (delete_this_wire) { | ||||||
| 		if (!used_signals_nodrivers.check_any(sig)) { | 			del_wires_queue.insert(wire); | ||||||
|  | 		} else { | ||||||
|  | 			RTLIL::SigSig new_conn; | ||||||
|  | 			for (int i = 0; i < GetSize(s1); i++) | ||||||
|  | 				if (s1[i] != s2[i]) { | ||||||
|  | 					if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) { | ||||||
|  | 						s2[i] = initval[i]; | ||||||
|  | 						initval[i] = State::Sx; | ||||||
|  | 					} | ||||||
|  | 					new_conn.first.append_bit(s1[i]); | ||||||
|  | 					new_conn.second.append_bit(s2[i]); | ||||||
|  | 				} | ||||||
|  | 			if (new_conn.first.size() > 0) { | ||||||
|  | 				if (initval.is_fully_undef()) | ||||||
|  | 					wire->attributes.erase("\\init"); | ||||||
|  | 				else | ||||||
|  | 					wire->attributes.at("\\init") = initval; | ||||||
|  | 				used_signals.add(new_conn.first); | ||||||
|  | 				used_signals.add(new_conn.second); | ||||||
|  | 				module->connect(new_conn); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (!used_signals_nodrivers.check_all(s2)) { | ||||||
| 			std::string unused_bits; | 			std::string unused_bits; | ||||||
| 			for (int i = 0; i < GetSize(sig); i++) { | 			for (int i = 0; i < GetSize(s2); i++) { | ||||||
| 				if (sig[i].wire == NULL) | 				if (s2[i].wire == NULL) | ||||||
| 					continue; | 					continue; | ||||||
| 				if (!used_signals_nodrivers.check(sig[i])) { | 				if (!used_signals_nodrivers.check(s2[i])) { | ||||||
| 					if (!unused_bits.empty()) | 					if (!unused_bits.empty()) | ||||||
| 						unused_bits += " "; | 						unused_bits += " "; | ||||||
| 					unused_bits += stringf("%d", i); | 					unused_bits += stringf("%d", i); | ||||||
|  | @ -362,24 +377,19 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	int del_temp_wires_count = 0; | ||||||
|  | 	for (auto wire : del_wires_queue) { | ||||||
|  | 		if (ys_debug() || (check_public_name(wire->name) && verbose)) | ||||||
|  | 			log_debug("  removing unused non-port wire %s.\n", wire->name.c_str()); | ||||||
|  | 		else | ||||||
|  | 			del_temp_wires_count++; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	pool<RTLIL::Wire*> del_wires; | 	module->remove(del_wires_queue); | ||||||
|  | 	count_rm_wires += GetSize(del_wires_queue); | ||||||
| 
 | 
 | ||||||
| 	int del_wires_count = 0; | 	if (verbose && del_temp_wires_count) | ||||||
| 	for (auto wire : maybe_del_wires) | 		log_debug("  removed %d unused temporary wires.\n", del_temp_wires_count); | ||||||
| 		if (!used_signals.check_any(RTLIL::SigSpec(wire))) { |  | ||||||
| 			if (check_public_name(wire->name) && verbose) { |  | ||||||
| 				log_debug("  removing unused non-port wire %s.\n", wire->name.c_str()); |  | ||||||
| 			} |  | ||||||
| 			del_wires.insert(wire); |  | ||||||
| 			del_wires_count++; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	module->remove(del_wires); |  | ||||||
| 	count_rm_wires += del_wires.size(); |  | ||||||
| 
 |  | ||||||
| 	if (verbose && del_wires_count > 0) |  | ||||||
| 		log_debug("  removed %d unused temporary wires.\n", del_wires_count); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) | bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) | ||||||
|  | @ -526,6 +536,9 @@ struct OptCleanPass : public Pass { | ||||||
| 
 | 
 | ||||||
| 		ct_all.setup(design); | 		ct_all.setup(design); | ||||||
| 
 | 
 | ||||||
|  | 		count_rm_cells = 0; | ||||||
|  | 		count_rm_wires = 0; | ||||||
|  | 
 | ||||||
| 		for (auto module : design->selected_whole_modules_warn()) { | 		for (auto module : design->selected_whole_modules_warn()) { | ||||||
| 			if (module->has_processes_warn()) | 			if (module->has_processes_warn()) | ||||||
| 				continue; | 				continue; | ||||||
|  | @ -591,7 +604,7 @@ struct CleanPass : public Pass { | ||||||
| 		for (auto module : design->selected_whole_modules()) { | 		for (auto module : design->selected_whole_modules()) { | ||||||
| 			if (module->has_processes()) | 			if (module->has_processes()) | ||||||
| 				continue; | 				continue; | ||||||
| 			rmunused_module(module, purge_mode, false, false); | 			rmunused_module(module, purge_mode, ys_debug(), false); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		log_suppressed(); | 		log_suppressed(); | ||||||
|  |  | ||||||
|  | @ -61,7 +61,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) | ||||||
| 		} | 		} | ||||||
| 		if (wire->port_input) | 		if (wire->port_input) | ||||||
| 			driven_signals.add(sigmap(wire)); | 			driven_signals.add(sigmap(wire)); | ||||||
| 		if (wire->port_output) | 		if (wire->port_output || wire->get_bool_attribute("\\keep")) | ||||||
| 			used_signals.add(sigmap(wire)); | 			used_signals.add(sigmap(wire)); | ||||||
| 		all_signals.add(sigmap(wire)); | 		all_signals.add(sigmap(wire)); | ||||||
| 	} | 	} | ||||||
|  | @ -88,7 +88,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		log_debug("Setting undriven signal in %s to constant: %s = %s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(val)); | 		log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val)); | ||||||
| 		module->connect(sig, val); | 		module->connect(sig, val); | ||||||
| 		did_something = true; | 		did_something = true; | ||||||
| 	} | 	} | ||||||
|  | @ -104,10 +104,15 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) | ||||||
| 				if (SigBit(initval[i]) == sig[i]) | 				if (SigBit(initval[i]) == sig[i]) | ||||||
| 					initval[i] = State::Sx; | 					initval[i] = State::Sx; | ||||||
| 			} | 			} | ||||||
| 			if (initval.is_fully_undef()) | 			if (initval.is_fully_undef()) { | ||||||
|  | 				log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire)); | ||||||
| 				wire->attributes.erase("\\init"); | 				wire->attributes.erase("\\init"); | ||||||
| 			else | 				did_something = true; | ||||||
|  | 			} else if (initval != wire->attributes.at("\\init")) { | ||||||
|  | 				log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval)); | ||||||
| 				wire->attributes["\\init"] = initval; | 				wire->attributes["\\init"] = initval; | ||||||
|  | 				did_something = true; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -531,6 +531,42 @@ struct WreducePass : public Pass { | ||||||
| 						module->connect(sig, Const(0, GetSize(sig))); | 						module->connect(sig, Const(0, GetSize(sig))); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | 
 | ||||||
|  | 				if (c->type.in("$div", "$mod", "$pow")) | ||||||
|  | 				{ | ||||||
|  | 					SigSpec A = c->getPort("\\A"); | ||||||
|  | 					int original_a_width = GetSize(A); | ||||||
|  | 					if (c->getParam("\\A_SIGNED").as_bool()) { | ||||||
|  | 						while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0) | ||||||
|  | 							A.remove(GetSize(A)-1, 1); | ||||||
|  | 					} else { | ||||||
|  | 						while (GetSize(A) > 0 && A[GetSize(A)-1] == State::S0) | ||||||
|  | 							A.remove(GetSize(A)-1, 1); | ||||||
|  | 					} | ||||||
|  | 					if (original_a_width != GetSize(A)) { | ||||||
|  | 						log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n", | ||||||
|  | 								original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type)); | ||||||
|  | 						c->setPort("\\A", A); | ||||||
|  | 						c->setParam("\\A_WIDTH", GetSize(A)); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					SigSpec B = c->getPort("\\B"); | ||||||
|  | 					int original_b_width = GetSize(B); | ||||||
|  | 					if (c->getParam("\\B_SIGNED").as_bool()) { | ||||||
|  | 						while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0) | ||||||
|  | 							B.remove(GetSize(B)-1, 1); | ||||||
|  | 					} else { | ||||||
|  | 						while (GetSize(B) > 0 && B[GetSize(B)-1] == State::S0) | ||||||
|  | 							B.remove(GetSize(B)-1, 1); | ||||||
|  | 					} | ||||||
|  | 					if (original_b_width != GetSize(B)) { | ||||||
|  | 						log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n", | ||||||
|  | 								original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type)); | ||||||
|  | 						c->setPort("\\B", B); | ||||||
|  | 						c->setParam("\\B_WIDTH", GetSize(B)); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
| 				if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) { | 				if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) { | ||||||
| 					IdString memid = c->getParam("\\MEMID").decode_string(); | 					IdString memid = c->getParam("\\MEMID").decode_string(); | ||||||
| 					RTLIL::Memory *mem = module->memories.at(memid); | 					RTLIL::Memory *mem = module->memories.at(memid); | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								passes/pmgen/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								passes/pmgen/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +1,2 @@ | ||||||
| /ice40_dsp_pm.h | /ice40_dsp_pm.h | ||||||
|  | /peepopt_pm.h | ||||||
|  |  | ||||||
|  | @ -1,8 +1,23 @@ | ||||||
| OBJS += passes/pmgen/ice40_dsp.o | OBJS += passes/pmgen/ice40_dsp.o | ||||||
|  | OBJS += passes/pmgen/peepopt.o | ||||||
|  | 
 | ||||||
|  | # --------------------------------------
 | ||||||
| 
 | 
 | ||||||
| passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h | passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h | ||||||
| EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h | EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h | ||||||
| .SECONDARY: passes/pmgen/ice40_dsp_pm.h | .SECONDARY: passes/pmgen/ice40_dsp_pm.h | ||||||
| 
 | 
 | ||||||
| passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg | passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg | ||||||
| 	$(P) mkdir -p passes/pmgen && python3 $^ $@ | 	$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_dsp $(filter-out $<,$^) | ||||||
|  | 
 | ||||||
|  | # --------------------------------------
 | ||||||
|  | 
 | ||||||
|  | passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h | ||||||
|  | EXTRA_OBJS += passes/pmgen/peepopt_pm.h | ||||||
|  | .SECONDARY: passes/pmgen/peepopt_pm.h | ||||||
|  | 
 | ||||||
|  | PEEPOPT_PATTERN  = passes/pmgen/peepopt_shiftmul.pmg | ||||||
|  | PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg | ||||||
|  | 
 | ||||||
|  | passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) | ||||||
|  | 	$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^) | ||||||
|  |  | ||||||
|  | @ -29,19 +29,25 @@ up in any future matches: | ||||||
| 
 | 
 | ||||||
|     pm.blacklist(some_cell); |     pm.blacklist(some_cell); | ||||||
| 
 | 
 | ||||||
| The `.run(callback_function)` method searches for all matches and calls the | The `.run_<pattern_name>(callback_function)` method searches for all matches | ||||||
| callback function for each found match: | for the pattern`<pattern_name>` and calls the callback function for each found | ||||||
|  | match: | ||||||
| 
 | 
 | ||||||
|     pm.run([&](){ |     pm.run_foobar([&](){ | ||||||
|         log("found matching 'foo' cell: %s\n", log_id(pm.st.foo)); |         log("found matching 'foo' cell: %s\n", log_id(pm.st.foo)); | ||||||
|         log("          with 'bar' cell: %s\n", log_id(pm.st.bar)); |         log("          with 'bar' cell: %s\n", log_id(pm.st.bar)); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
| The `.pmg` file declares matcher state variables that are accessible via the | The `.pmg` file declares matcher state variables that are accessible via the | ||||||
| `.st.<state_name>` members. (The `.st` member is of type `foobar_pm::state_t`.) | `.st_<pattern_name>.<state_name>` members. (The `.st_<pattern_name>` member is | ||||||
|  | of type `foobar_pm::state_<pattern_name>_t`.) | ||||||
| 
 | 
 | ||||||
| Similarly the `.pmg` file declares user data variables that become members of | Similarly the `.pmg` file declares user data variables that become members of | ||||||
| `.ud`, a struct of type `foobar_pm::udata_t`. | `.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`. | ||||||
|  | 
 | ||||||
|  | There are four versions of the `run_<pattern_name>()` method: Without callback, | ||||||
|  | callback without arguments, callback with reference to `pm`, and callback with | ||||||
|  | reference to `pm.st_<pattern_name>`. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| The .pmg File Format | The .pmg File Format | ||||||
|  | @ -52,6 +58,12 @@ lines consist of whitespace-separated tokens. | ||||||
| 
 | 
 | ||||||
| Lines in `.pmg` files starting with `//` are comments. | Lines in `.pmg` files starting with `//` are comments. | ||||||
| 
 | 
 | ||||||
|  | Declaring a pattern | ||||||
|  | ------------------- | ||||||
|  | 
 | ||||||
|  | A `.pmg` file contains one or more patterns. Each pattern starts with a line | ||||||
|  | with the `pattern` keyword followed by the name of the pattern. | ||||||
|  | 
 | ||||||
| Declaring state variables | Declaring state variables | ||||||
| ------------------------- | ------------------------- | ||||||
| 
 | 
 | ||||||
|  | @ -66,7 +78,7 @@ State variables are automatically managed by the generated backtracking algorith | ||||||
| and saved and restored as needed. | and saved and restored as needed. | ||||||
| 
 | 
 | ||||||
| They are automatically initialized to the default constructed value of their type | They are automatically initialized to the default constructed value of their type | ||||||
| when `.run(callback_function)` is called. | when `.run_<pattern_name>(callback_function)` is called. | ||||||
| 
 | 
 | ||||||
| Declaring udata variables | Declaring udata variables | ||||||
| ------------------------- | ------------------------- | ||||||
|  |  | ||||||
|  | @ -19,47 +19,50 @@ | ||||||
| 
 | 
 | ||||||
| #include "kernel/yosys.h" | #include "kernel/yosys.h" | ||||||
| #include "kernel/sigtools.h" | #include "kernel/sigtools.h" | ||||||
| #include "passes/pmgen/ice40_dsp_pm.h" |  | ||||||
| 
 | 
 | ||||||
| USING_YOSYS_NAMESPACE | USING_YOSYS_NAMESPACE | ||||||
| PRIVATE_NAMESPACE_BEGIN | PRIVATE_NAMESPACE_BEGIN | ||||||
| 
 | 
 | ||||||
|  | #include "passes/pmgen/ice40_dsp_pm.h" | ||||||
|  | 
 | ||||||
| void create_ice40_dsp(ice40_dsp_pm &pm) | void create_ice40_dsp(ice40_dsp_pm &pm) | ||||||
| { | { | ||||||
|  | 	auto &st = pm.st_ice40_dsp; | ||||||
|  | 
 | ||||||
| #if 0 | #if 0 | ||||||
| 	log("\n"); | 	log("\n"); | ||||||
| 	log("ffA:   %s\n", log_id(pm.st.ffA, "--")); | 	log("ffA:   %s\n", log_id(st.ffA, "--")); | ||||||
| 	log("ffB:   %s\n", log_id(pm.st.ffB, "--")); | 	log("ffB:   %s\n", log_id(st.ffB, "--")); | ||||||
| 	log("mul:   %s\n", log_id(pm.st.mul, "--")); | 	log("mul:   %s\n", log_id(st.mul, "--")); | ||||||
| 	log("ffY:   %s\n", log_id(pm.st.ffY, "--")); | 	log("ffY:   %s\n", log_id(st.ffY, "--")); | ||||||
| 	log("addAB: %s\n", log_id(pm.st.addAB, "--")); | 	log("addAB: %s\n", log_id(st.addAB, "--")); | ||||||
| 	log("muxAB: %s\n", log_id(pm.st.muxAB, "--")); | 	log("muxAB: %s\n", log_id(st.muxAB, "--")); | ||||||
| 	log("ffS:   %s\n", log_id(pm.st.ffS, "--")); | 	log("ffS:   %s\n", log_id(st.ffS, "--")); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(pm.st.mul)); | 	log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); | ||||||
| 
 | 
 | ||||||
| 	if (GetSize(pm.st.sigA) > 16) { | 	if (GetSize(st.sigA) > 16) { | ||||||
| 		log("  input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA)); | 		log("  input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA)); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (GetSize(pm.st.sigB) > 16) { | 	if (GetSize(st.sigB) > 16) { | ||||||
| 		log("  input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB)); | 		log("  input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB)); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (GetSize(pm.st.sigS) > 32) { | 	if (GetSize(st.sigS) > 32) { | ||||||
| 		log("  accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS)); | 		log("  accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS)); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (GetSize(pm.st.sigY) > 32) { | 	if (GetSize(st.sigY) > 32) { | ||||||
| 		log("  output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY)); | 		log("  output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY)); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool mul_signed = pm.st.mul->getParam("\\A_SIGNED").as_bool(); | 	bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool(); | ||||||
| 
 | 
 | ||||||
| 	if (mul_signed) { | 	if (mul_signed) { | ||||||
| 		log("  inference of signed iCE40 DSP arithmetic is currently not supported.\n"); | 		log("  inference of signed iCE40 DSP arithmetic is currently not supported.\n"); | ||||||
|  | @ -69,21 +72,21 @@ void create_ice40_dsp(ice40_dsp_pm &pm) | ||||||
| 	log("  replacing $mul with SB_MAC16 cell.\n"); | 	log("  replacing $mul with SB_MAC16 cell.\n"); | ||||||
| 
 | 
 | ||||||
| 	Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); | 	Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); | ||||||
| 	pm.module->swap_names(cell, pm.st.mul); | 	pm.module->swap_names(cell, st.mul); | ||||||
| 
 | 
 | ||||||
| 	// SB_MAC16 Input Interface
 | 	// SB_MAC16 Input Interface
 | ||||||
| 
 | 
 | ||||||
| 	SigSpec A = pm.st.sigA; | 	SigSpec A = st.sigA; | ||||||
| 	A.extend_u0(16, mul_signed); | 	A.extend_u0(16, mul_signed); | ||||||
| 
 | 
 | ||||||
| 	SigSpec B = pm.st.sigB; | 	SigSpec B = st.sigB; | ||||||
| 	B.extend_u0(16, mul_signed); | 	B.extend_u0(16, mul_signed); | ||||||
| 
 | 
 | ||||||
| 	SigSpec CD; | 	SigSpec CD; | ||||||
| 	if (pm.st.muxA) | 	if (st.muxA) | ||||||
| 		CD = pm.st.muxA->getPort("\\B"); | 		CD = st.muxA->getPort("\\B"); | ||||||
| 	if (pm.st.muxB) | 	if (st.muxB) | ||||||
| 		CD = pm.st.muxB->getPort("\\A"); | 		CD = st.muxB->getPort("\\A"); | ||||||
| 	CD.extend_u0(32, mul_signed); | 	CD.extend_u0(32, mul_signed); | ||||||
| 
 | 
 | ||||||
| 	cell->setPort("\\A", A); | 	cell->setPort("\\A", A); | ||||||
|  | @ -91,8 +94,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) | ||||||
| 	cell->setPort("\\C", CD.extract(0, 16)); | 	cell->setPort("\\C", CD.extract(0, 16)); | ||||||
| 	cell->setPort("\\D", CD.extract(16, 16)); | 	cell->setPort("\\D", CD.extract(16, 16)); | ||||||
| 
 | 
 | ||||||
| 	cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0); | 	cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0); | ||||||
| 	cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0); | 	cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0); | ||||||
| 
 | 
 | ||||||
| 	cell->setPort("\\AHOLD", State::S0); | 	cell->setPort("\\AHOLD", State::S0); | ||||||
| 	cell->setPort("\\BHOLD", State::S0); | 	cell->setPort("\\BHOLD", State::S0); | ||||||
|  | @ -102,25 +105,25 @@ void create_ice40_dsp(ice40_dsp_pm &pm) | ||||||
| 	cell->setPort("\\IRSTTOP", State::S0); | 	cell->setPort("\\IRSTTOP", State::S0); | ||||||
| 	cell->setPort("\\IRSTBOT", State::S0); | 	cell->setPort("\\IRSTBOT", State::S0); | ||||||
| 
 | 
 | ||||||
| 	if (pm.st.clock_vld) | 	if (st.clock_vld) | ||||||
| 	{ | 	{ | ||||||
| 		cell->setPort("\\CLK", pm.st.clock); | 		cell->setPort("\\CLK", st.clock); | ||||||
| 		cell->setPort("\\CE", State::S1); | 		cell->setPort("\\CE", State::S1); | ||||||
| 		cell->setParam("\\NEG_TRIGGER", pm.st.clock_pol ? State::S0 : State::S1); | 		cell->setParam("\\NEG_TRIGGER", st.clock_pol ? State::S0 : State::S1); | ||||||
| 
 | 
 | ||||||
| 		log("  clock: %s (%s)", log_signal(pm.st.clock), pm.st.clock_pol ? "posedge" : "negedge"); | 		log("  clock: %s (%s)", log_signal(st.clock), st.clock_pol ? "posedge" : "negedge"); | ||||||
| 
 | 
 | ||||||
| 		if (pm.st.ffA) | 		if (st.ffA) | ||||||
| 			log(" ffA:%s", log_id(pm.st.ffA)); | 			log(" ffA:%s", log_id(st.ffA)); | ||||||
| 
 | 
 | ||||||
| 		if (pm.st.ffB) | 		if (st.ffB) | ||||||
| 			log(" ffB:%s", log_id(pm.st.ffB)); | 			log(" ffB:%s", log_id(st.ffB)); | ||||||
| 
 | 
 | ||||||
| 		if (pm.st.ffY) | 		if (st.ffY) | ||||||
| 			log(" ffY:%s", log_id(pm.st.ffY)); | 			log(" ffY:%s", log_id(st.ffY)); | ||||||
| 
 | 
 | ||||||
| 		if (pm.st.ffS) | 		if (st.ffS) | ||||||
| 			log(" ffS:%s", log_id(pm.st.ffS)); | 			log(" ffS:%s", log_id(st.ffS)); | ||||||
| 
 | 
 | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 	} | 	} | ||||||
|  | @ -144,16 +147,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm) | ||||||
| 
 | 
 | ||||||
| 	// SB_MAC16 Output Interface
 | 	// SB_MAC16 Output Interface
 | ||||||
| 
 | 
 | ||||||
| 	SigSpec O = pm.st.ffS ? pm.st.sigS : pm.st.sigY; | 	SigSpec O = st.ffS ? st.sigS : st.sigY; | ||||||
| 	if (GetSize(O) < 32) | 	if (GetSize(O) < 32) | ||||||
| 		O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); | 		O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); | ||||||
| 
 | 
 | ||||||
| 	cell->setPort("\\O", O); | 	cell->setPort("\\O", O); | ||||||
| 
 | 
 | ||||||
| 	if (pm.st.addAB) { | 	if (st.addAB) { | ||||||
| 		log("  accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type)); | 		log("  accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); | ||||||
| 		cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1); | 		cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1); | ||||||
| 		cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1); | 		cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1); | ||||||
| 	} else { | 	} else { | ||||||
| 		cell->setPort("\\ADDSUBTOP", State::S0); | 		cell->setPort("\\ADDSUBTOP", State::S0); | ||||||
| 		cell->setPort("\\ADDSUBBOT", State::S0); | 		cell->setPort("\\ADDSUBBOT", State::S0); | ||||||
|  | @ -166,10 +169,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) | ||||||
| 	cell->setPort("\\OHOLDBOT", State::S0); | 	cell->setPort("\\OHOLDBOT", State::S0); | ||||||
| 
 | 
 | ||||||
| 	SigSpec acc_reset = State::S0; | 	SigSpec acc_reset = State::S0; | ||||||
| 	if (pm.st.muxA) | 	if (st.muxA) | ||||||
| 		acc_reset = pm.st.muxA->getPort("\\S"); | 		acc_reset = st.muxA->getPort("\\S"); | ||||||
| 	if (pm.st.muxB) | 	if (st.muxB) | ||||||
| 		acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S")); | 		acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S")); | ||||||
| 
 | 
 | ||||||
| 	cell->setPort("\\OLOADTOP", acc_reset); | 	cell->setPort("\\OLOADTOP", acc_reset); | ||||||
| 	cell->setPort("\\OLOADBOT", acc_reset); | 	cell->setPort("\\OLOADBOT", acc_reset); | ||||||
|  | @ -179,17 +182,17 @@ void create_ice40_dsp(ice40_dsp_pm &pm) | ||||||
| 	cell->setParam("\\C_REG", State::S0); | 	cell->setParam("\\C_REG", State::S0); | ||||||
| 	cell->setParam("\\D_REG", State::S0); | 	cell->setParam("\\D_REG", State::S0); | ||||||
| 
 | 
 | ||||||
| 	cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); | 	cell->setParam("\\TOP_8x8_MULT_REG", st.ffY ? State::S1 : State::S0); | ||||||
| 	cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); | 	cell->setParam("\\BOT_8x8_MULT_REG", st.ffY ? State::S1 : State::S0); | ||||||
| 	cell->setParam("\\PIPELINE_16x16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0); | 	cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffY ? State::S1 : State::S0); | ||||||
| 	cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); | 	cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); | ||||||
| 
 | 
 | ||||||
| 	cell->setParam("\\TOPOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); | 	cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2)); | ||||||
| 	cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); | 	cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); | ||||||
| 	cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0); | 	cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0); | ||||||
| 	cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); | 	cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); | ||||||
| 
 | 
 | ||||||
| 	cell->setParam("\\BOTOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); | 	cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2)); | ||||||
| 	cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); | 	cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); | ||||||
| 	cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0); | 	cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0); | ||||||
| 	cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); | 	cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); | ||||||
|  | @ -198,9 +201,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm) | ||||||
| 	cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0); | 	cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0); | ||||||
| 	cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0); | 	cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0); | ||||||
| 
 | 
 | ||||||
| 	pm.autoremove(pm.st.mul); | 	pm.autoremove(st.mul); | ||||||
| 	pm.autoremove(pm.st.ffY); | 	pm.autoremove(st.ffY); | ||||||
| 	pm.autoremove(pm.st.ffS); | 	pm.autoremove(st.ffS); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct Ice40DspPass : public Pass { | struct Ice40DspPass : public Pass { | ||||||
|  | @ -230,7 +233,7 @@ struct Ice40DspPass : public Pass { | ||||||
| 		extra_args(args, argidx, design); | 		extra_args(args, argidx, design); | ||||||
| 
 | 
 | ||||||
| 		for (auto module : design->selected_modules()) | 		for (auto module : design->selected_modules()) | ||||||
| 			ice40_dsp_pm(module, module->selected_cells()).run(create_ice40_dsp); | 			ice40_dsp_pm(module, module->selected_cells()).run_ice40_dsp(create_ice40_dsp); | ||||||
| 	} | 	} | ||||||
| } Ice40DspPass; | } Ice40DspPass; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,3 +1,5 @@ | ||||||
|  | pattern ice40_dsp | ||||||
|  | 
 | ||||||
| state <SigBit> clock | state <SigBit> clock | ||||||
| state <bool> clock_pol clock_vld | state <bool> clock_pol clock_vld | ||||||
| state <SigSpec> sigA sigB sigY sigS | state <SigSpec> sigA sigB sigY sigS | ||||||
|  |  | ||||||
							
								
								
									
										68
									
								
								passes/pmgen/peepopt.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								passes/pmgen/peepopt.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | ||||||
|  | /*
 | ||||||
|  |  *  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. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "kernel/yosys.h" | ||||||
|  | #include "kernel/sigtools.h" | ||||||
|  | 
 | ||||||
|  | USING_YOSYS_NAMESPACE | ||||||
|  | PRIVATE_NAMESPACE_BEGIN | ||||||
|  | 
 | ||||||
|  | bool did_something; | ||||||
|  | 
 | ||||||
|  | #include "passes/pmgen/peepopt_pm.h" | ||||||
|  | 
 | ||||||
|  | struct PeepoptPass : public Pass { | ||||||
|  | 	PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { } | ||||||
|  | 	void help() YS_OVERRIDE | ||||||
|  | 	{ | ||||||
|  | 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    peepopt [options] [selection]\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("This pass applies a collection of peephole optimizers to the current design.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 	} | ||||||
|  | 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||||
|  | 	{ | ||||||
|  | 		log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n"); | ||||||
|  | 
 | ||||||
|  | 		size_t argidx; | ||||||
|  | 		for (argidx = 1; argidx < args.size(); argidx++) | ||||||
|  | 		{ | ||||||
|  | 			// if (args[argidx] == "-singleton") {
 | ||||||
|  | 			// 	singleton_mode = true;
 | ||||||
|  | 			// 	continue;
 | ||||||
|  | 			// }
 | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		extra_args(args, argidx, design); | ||||||
|  | 
 | ||||||
|  | 		for (auto module : design->selected_modules()) { | ||||||
|  | 			did_something = true; | ||||||
|  | 			while (did_something) { | ||||||
|  | 				did_something = false; | ||||||
|  | 				peepopt_pm pm(module, module->selected_cells()); | ||||||
|  | 				pm.run_shiftmul(); | ||||||
|  | 				pm.run_muldiv(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } PeepoptPass; | ||||||
|  | 
 | ||||||
|  | PRIVATE_NAMESPACE_END | ||||||
							
								
								
									
										36
									
								
								passes/pmgen/peepopt_muldiv.pmg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								passes/pmgen/peepopt_muldiv.pmg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | pattern muldiv | ||||||
|  | 
 | ||||||
|  | state <SigSpec> t x y | ||||||
|  | 
 | ||||||
|  | match mul | ||||||
|  | 	select mul->type == $mul | ||||||
|  | 	select GetSize(port(mul, \A)) + GetSize(port(mul, \B)) <= GetSize(port(mul, \Y)) | ||||||
|  | endmatch | ||||||
|  | 
 | ||||||
|  | code t x y | ||||||
|  | 	t = port(mul, \Y); | ||||||
|  | 	x = port(mul, \A); | ||||||
|  | 	y = port(mul, \B); | ||||||
|  | 	branch; | ||||||
|  | 	std::swap(x, y); | ||||||
|  | endcode | ||||||
|  | 
 | ||||||
|  | match div | ||||||
|  | 	select div->type.in($div) | ||||||
|  | 	index <SigSpec> port(div, \A) === t | ||||||
|  | 	index <SigSpec> port(div, \B) === x | ||||||
|  | endmatch | ||||||
|  | 
 | ||||||
|  | code | ||||||
|  | 	SigSpec div_y = port(div, \Y); | ||||||
|  | 	SigSpec val_y = y; | ||||||
|  | 
 | ||||||
|  | 	if (GetSize(div_y) != GetSize(val_y)) | ||||||
|  | 		val_y.extend_u0(GetSize(div_y), param(div, \A_SIGNED).as_bool()); | ||||||
|  | 
 | ||||||
|  | 	did_something = true; | ||||||
|  | 	log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div)); | ||||||
|  | 	module->connect(div_y, val_y); | ||||||
|  | 	autoremove(div); | ||||||
|  | 	reject; | ||||||
|  | endcode | ||||||
							
								
								
									
										87
									
								
								passes/pmgen/peepopt_shiftmul.pmg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								passes/pmgen/peepopt_shiftmul.pmg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,87 @@ | ||||||
|  | pattern shiftmul | ||||||
|  | 
 | ||||||
|  | state <SigSpec> shamt | ||||||
|  | 
 | ||||||
|  | match shift | ||||||
|  | 	select shift->type.in($shift, $shiftx, $shr) | ||||||
|  | endmatch | ||||||
|  | 
 | ||||||
|  | code shamt | ||||||
|  | 	shamt = port(shift, \B); | ||||||
|  | 	if (shamt.empty()) | ||||||
|  | 		reject; | ||||||
|  | 	if (shamt[GetSize(shamt)-1] == State::S0) { | ||||||
|  | 		do { | ||||||
|  | 			shamt.remove(GetSize(shamt)-1); | ||||||
|  | 			if (shamt.empty()) | ||||||
|  | 				reject; | ||||||
|  | 		} while (shamt[GetSize(shamt)-1] == State::S0); | ||||||
|  | 	} else | ||||||
|  | 	if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) { | ||||||
|  | 		reject; | ||||||
|  | 	} | ||||||
|  | 	if (GetSize(shamt) > 20) | ||||||
|  | 		reject; | ||||||
|  | endcode | ||||||
|  | 
 | ||||||
|  | match mul | ||||||
|  | 	select mul->type.in($mul) | ||||||
|  | 	select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const() | ||||||
|  | 	index <SigSpec> port(mul, \Y) === shamt | ||||||
|  | endmatch | ||||||
|  | 
 | ||||||
|  | code | ||||||
|  | 	IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B; | ||||||
|  | 	IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED; | ||||||
|  | 	Const const_factor_cnst = port(mul, const_factor_port).as_const(); | ||||||
|  | 	int const_factor = const_factor_cnst.as_int(); | ||||||
|  | 
 | ||||||
|  | 	if (GetSize(const_factor_cnst) == 0) | ||||||
|  | 		reject; | ||||||
|  | 
 | ||||||
|  | 	if (const_factor_cnst.bits[GetSize(const_factor_cnst)-1] != State::S0 && | ||||||
|  | 			param(mul, const_factor_signed).as_bool()) | ||||||
|  | 		reject; | ||||||
|  | 
 | ||||||
|  | 	if (GetSize(const_factor_cnst) > 20) | ||||||
|  | 		reject; | ||||||
|  | 
 | ||||||
|  | 	if (GetSize(port(shift, \Y)) > const_factor) | ||||||
|  | 		reject; | ||||||
|  | 
 | ||||||
|  | 	did_something = true; | ||||||
|  | 	log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); | ||||||
|  | 
 | ||||||
|  | 	int new_const_factor_log2 = ceil_log2(const_factor); | ||||||
|  | 	int new_const_factor = 1 << new_const_factor_log2; | ||||||
|  | 
 | ||||||
|  | 	SigSpec padding(State::Sx, new_const_factor-const_factor); | ||||||
|  | 	SigSpec old_a = port(shift, \A), new_a; | ||||||
|  | 	int trunc = 0; | ||||||
|  | 
 | ||||||
|  | 	if (GetSize(old_a) % const_factor != 0) { | ||||||
|  | 		trunc = const_factor - GetSize(old_a) % const_factor; | ||||||
|  | 		old_a.append(SigSpec(State::Sx, trunc)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for (int i = 0; i*const_factor < GetSize(old_a); i++) { | ||||||
|  | 		SigSpec slice = old_a.extract(i*const_factor, const_factor); | ||||||
|  | 		new_a.append(slice); | ||||||
|  | 		new_a.append(padding); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (trunc > 0) | ||||||
|  | 		new_a.remove(GetSize(new_a)-trunc, trunc); | ||||||
|  | 
 | ||||||
|  | 	SigSpec new_b = {port(mul, const_factor_port == \A ? \B : \A), SigSpec(State::S0, new_const_factor_log2)}; | ||||||
|  | 	if (param(shift, \B_SIGNED).as_bool()) | ||||||
|  | 		new_b.append(State::S0); | ||||||
|  | 
 | ||||||
|  | 	shift->setPort(\A, new_a); | ||||||
|  | 	shift->setParam(\A_WIDTH, GetSize(new_a)); | ||||||
|  | 	shift->setPort(\B, new_b); | ||||||
|  | 	shift->setParam(\B_WIDTH, GetSize(new_b)); | ||||||
|  | 
 | ||||||
|  | 	blacklist(shift); | ||||||
|  | 	reject; | ||||||
|  | endcode | ||||||
|  | @ -3,15 +3,42 @@ | ||||||
| import re | import re | ||||||
| import sys | import sys | ||||||
| import pprint | import pprint | ||||||
|  | import getopt | ||||||
| 
 | 
 | ||||||
| pp = pprint.PrettyPrinter(indent=4) | pp = pprint.PrettyPrinter(indent=4) | ||||||
| 
 | 
 | ||||||
| pmgfile = sys.argv[1] | prefix = None | ||||||
| assert pmgfile.endswith(".pmg") | pmgfiles = list() | ||||||
| prefix = pmgfile[0:-4] | outfile = None | ||||||
| prefix = prefix.split('/')[-1] | debug = False | ||||||
| outfile = sys.argv[2] | genhdr = False | ||||||
| 
 | 
 | ||||||
|  | opts, args = getopt.getopt(sys.argv[1:], "p:o:dg") | ||||||
|  | 
 | ||||||
|  | for o, a in opts: | ||||||
|  |     if o == "-p": | ||||||
|  |         prefix = a | ||||||
|  |     elif o == "-o": | ||||||
|  |         outfile = a | ||||||
|  |     elif o == "-d": | ||||||
|  |         debug = True | ||||||
|  |     elif o == "-g": | ||||||
|  |         genhdr = True | ||||||
|  | 
 | ||||||
|  | if outfile is None: | ||||||
|  |     outfile = "/dev/stdout" | ||||||
|  | 
 | ||||||
|  | for a in args: | ||||||
|  |     assert a.endswith(".pmg") | ||||||
|  |     if prefix is None and len(args) == 1: | ||||||
|  |         prefix = a[0:-4] | ||||||
|  |         prefix = prefix.split('/')[-1] | ||||||
|  |     pmgfiles.append(a) | ||||||
|  | 
 | ||||||
|  | assert prefix is not None | ||||||
|  | 
 | ||||||
|  | current_pattern = None | ||||||
|  | patterns = dict() | ||||||
| state_types = dict() | state_types = dict() | ||||||
| udata_types = dict() | udata_types = dict() | ||||||
| blocks = list() | blocks = list() | ||||||
|  | @ -77,7 +104,8 @@ def rewrite_cpp(s): | ||||||
| 
 | 
 | ||||||
|     return "".join(t) |     return "".join(t) | ||||||
| 
 | 
 | ||||||
| with open(pmgfile, "r") as f: | def process_pmgfile(f): | ||||||
|  |     global current_pattern | ||||||
|     while True: |     while True: | ||||||
|         line = f.readline() |         line = f.readline() | ||||||
|         if line == "": break |         if line == "": break | ||||||
|  | @ -87,14 +115,31 @@ with open(pmgfile, "r") as f: | ||||||
|         if len(cmd) == 0 or cmd[0].startswith("//"): continue |         if len(cmd) == 0 or cmd[0].startswith("//"): continue | ||||||
|         cmd = cmd[0] |         cmd = cmd[0] | ||||||
| 
 | 
 | ||||||
|  |         if cmd == "pattern": | ||||||
|  |             if current_pattern is not None: | ||||||
|  |                 block = dict() | ||||||
|  |                 block["type"] = "final" | ||||||
|  |                 block["pattern"] = current_pattern | ||||||
|  |                 blocks.append(block) | ||||||
|  |             line = line.split() | ||||||
|  |             assert len(line) == 2 | ||||||
|  |             assert line[1] not in patterns | ||||||
|  |             current_pattern = line[1] | ||||||
|  |             patterns[current_pattern] = len(blocks) | ||||||
|  |             state_types[current_pattern] = dict() | ||||||
|  |             udata_types[current_pattern] = dict() | ||||||
|  |             continue | ||||||
|  | 
 | ||||||
|  |         assert current_pattern is not None | ||||||
|  | 
 | ||||||
|         if cmd == "state": |         if cmd == "state": | ||||||
|             m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) |             m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) | ||||||
|             assert m |             assert m | ||||||
|             type_str = m.group(1) |             type_str = m.group(1) | ||||||
|             states_str = m.group(2) |             states_str = m.group(2) | ||||||
|             for s in re.split(r"\s+", states_str): |             for s in re.split(r"\s+", states_str): | ||||||
|                 assert s not in state_types |                 assert s not in state_types[current_pattern] | ||||||
|                 state_types[s] = type_str |                 state_types[current_pattern][s] = type_str | ||||||
|             continue |             continue | ||||||
| 
 | 
 | ||||||
|         if cmd == "udata": |         if cmd == "udata": | ||||||
|  | @ -103,19 +148,20 @@ with open(pmgfile, "r") as f: | ||||||
|             type_str = m.group(1) |             type_str = m.group(1) | ||||||
|             udatas_str = m.group(2) |             udatas_str = m.group(2) | ||||||
|             for s in re.split(r"\s+", udatas_str): |             for s in re.split(r"\s+", udatas_str): | ||||||
|                 assert s not in udata_types |                 assert s not in udata_types[current_pattern] | ||||||
|                 udata_types[s] = type_str |                 udata_types[current_pattern][s] = type_str | ||||||
|             continue |             continue | ||||||
| 
 | 
 | ||||||
|         if cmd == "match": |         if cmd == "match": | ||||||
|             block = dict() |             block = dict() | ||||||
|             block["type"] = "match" |             block["type"] = "match" | ||||||
|  |             block["pattern"] = current_pattern | ||||||
| 
 | 
 | ||||||
|             line = line.split() |             line = line.split() | ||||||
|             assert len(line) == 2 |             assert len(line) == 2 | ||||||
|             assert line[1] not in state_types |             assert line[1] not in state_types[current_pattern] | ||||||
|             block["cell"] = line[1] |             block["cell"] = line[1] | ||||||
|             state_types[line[1]] = "Cell*"; |             state_types[current_pattern][line[1]] = "Cell*"; | ||||||
| 
 | 
 | ||||||
|             block["if"] = list() |             block["if"] = list() | ||||||
|             block["select"] = list() |             block["select"] = list() | ||||||
|  | @ -158,15 +204,18 @@ with open(pmgfile, "r") as f: | ||||||
|                 assert False |                 assert False | ||||||
| 
 | 
 | ||||||
|             blocks.append(block) |             blocks.append(block) | ||||||
|  |             continue | ||||||
| 
 | 
 | ||||||
|         if cmd == "code": |         if cmd == "code": | ||||||
|             block = dict() |             block = dict() | ||||||
|             block["type"] = "code" |             block["type"] = "code" | ||||||
|  |             block["pattern"] = current_pattern | ||||||
|  | 
 | ||||||
|             block["code"] = list() |             block["code"] = list() | ||||||
|             block["states"] = set() |             block["states"] = set() | ||||||
| 
 | 
 | ||||||
|             for s in line.split()[1:]: |             for s in line.split()[1:]: | ||||||
|                 assert s in state_types |                 assert s in state_types[current_pattern] | ||||||
|                 block["states"].add(s) |                 block["states"].add(s) | ||||||
| 
 | 
 | ||||||
|             while True: |             while True: | ||||||
|  | @ -179,17 +228,36 @@ with open(pmgfile, "r") as f: | ||||||
|                 block["code"].append(rewrite_cpp(l.rstrip())) |                 block["code"].append(rewrite_cpp(l.rstrip())) | ||||||
| 
 | 
 | ||||||
|             blocks.append(block) |             blocks.append(block) | ||||||
|  |             continue | ||||||
|  | 
 | ||||||
|  |         assert False | ||||||
|  | 
 | ||||||
|  | for fn in pmgfiles: | ||||||
|  |     with open(fn, "r") as f: | ||||||
|  |         process_pmgfile(f) | ||||||
|  | 
 | ||||||
|  | if current_pattern is not None: | ||||||
|  |     block = dict() | ||||||
|  |     block["type"] = "final" | ||||||
|  |     block["pattern"] = current_pattern | ||||||
|  |     blocks.append(block) | ||||||
|  | 
 | ||||||
|  | current_pattern = None | ||||||
|  | 
 | ||||||
|  | if debug: | ||||||
|  |     pp.pprint(blocks) | ||||||
| 
 | 
 | ||||||
| with open(outfile, "w") as f: | with open(outfile, "w") as f: | ||||||
|     print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) |     for fn in pmgfiles: | ||||||
|  |         print("// Generated by pmgen.py from {}".format(fn), file=f) | ||||||
|     print("", file=f) |     print("", file=f) | ||||||
| 
 | 
 | ||||||
|     print("#include \"kernel/yosys.h\"", file=f) |     if genhdr: | ||||||
|     print("#include \"kernel/sigtools.h\"", file=f) |         print("#include \"kernel/yosys.h\"", file=f) | ||||||
|     print("", file=f) |         print("#include \"kernel/sigtools.h\"", file=f) | ||||||
| 
 |         print("", file=f) | ||||||
|     print("YOSYS_NAMESPACE_BEGIN", file=f) |         print("YOSYS_NAMESPACE_BEGIN", file=f) | ||||||
|     print("", file=f) |         print("", file=f) | ||||||
| 
 | 
 | ||||||
|     print("struct {}_pm {{".format(prefix), file=f) |     print("struct {}_pm {{".format(prefix), file=f) | ||||||
|     print("  Module *module;", file=f) |     print("  Module *module;", file=f) | ||||||
|  | @ -212,17 +280,19 @@ with open(outfile, "w") as f: | ||||||
|     print("  int rollback;", file=f) |     print("  int rollback;", file=f) | ||||||
|     print("", file=f) |     print("", file=f) | ||||||
| 
 | 
 | ||||||
|     print("  struct state_t {", file=f) |     for current_pattern in sorted(patterns.keys()): | ||||||
|     for s, t in sorted(state_types.items()): |         print("  struct state_{}_t {{".format(current_pattern), file=f) | ||||||
|         print("    {} {};".format(t, s), file=f) |         for s, t in sorted(state_types[current_pattern].items()): | ||||||
|     print("  } st;", file=f) |             print("    {} {};".format(t, s), file=f) | ||||||
|     print("", file=f) |         print("  }} st_{};".format(current_pattern), file=f) | ||||||
|  |         print("", file=f) | ||||||
| 
 | 
 | ||||||
|     print("  struct udata_t {", file=f) |         print("  struct udata_{}_t {{".format(current_pattern), file=f) | ||||||
|     for s, t in sorted(udata_types.items()): |         for s, t in sorted(udata_types[current_pattern].items()): | ||||||
|         print("    {} {};".format(t, s), file=f) |             print("    {} {};".format(t, s), file=f) | ||||||
|     print("  } ud;", file=f) |         print("  }} ud_{};".format(current_pattern), file=f) | ||||||
|     print("", file=f) |         print("", file=f) | ||||||
|  |     current_pattern = None | ||||||
| 
 | 
 | ||||||
|     for v, n in sorted(ids.items()): |     for v, n in sorted(ids.items()): | ||||||
|         if n[0] == "\\": |         if n[0] == "\\": | ||||||
|  | @ -258,20 +328,24 @@ with open(outfile, "w") as f: | ||||||
|     print("  }", file=f) |     print("  }", file=f) | ||||||
|     print("", file=f) |     print("", file=f) | ||||||
| 
 | 
 | ||||||
|     print("  void check_blacklist() {", file=f) |     for current_pattern in sorted(patterns.keys()): | ||||||
|     print("    if (!blacklist_dirty)", file=f) |         print("  void check_blacklist_{}() {{".format(current_pattern), file=f) | ||||||
|     print("      return;", file=f) |         print("    if (!blacklist_dirty)", file=f) | ||||||
|     print("    blacklist_dirty = false;", file=f) |         print("      return;", file=f) | ||||||
|     for index in range(len(blocks)): |         print("    blacklist_dirty = false;", file=f) | ||||||
|         block = blocks[index] |         for index in range(len(blocks)): | ||||||
|         if block["type"] == "match": |             block = blocks[index] | ||||||
|             print("    if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f) |             if block["pattern"] != current_pattern: | ||||||
|             print("      rollback = {};".format(index+1), file=f) |                 continue | ||||||
|             print("      return;", file=f) |             if block["type"] == "match": | ||||||
|             print("    }", file=f) |                 print("    if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f) | ||||||
|     print("    rollback = 0;", file=f) |                 print("      rollback = {};".format(index+1), file=f) | ||||||
|     print("  }", file=f) |                 print("      return;", file=f) | ||||||
|     print("", file=f) |                 print("    }", file=f) | ||||||
|  |         print("    rollback = 0;", file=f) | ||||||
|  |         print("  }", file=f) | ||||||
|  |         print("", file=f) | ||||||
|  |     current_pattern = None | ||||||
| 
 | 
 | ||||||
|     print("  SigSpec port(Cell *cell, IdString portname) {", file=f) |     print("  SigSpec port(Cell *cell, IdString portname) {", file=f) | ||||||
|     print("    return sigmap(cell->getPort(portname));", file=f) |     print("    return sigmap(cell->getPort(portname));", file=f) | ||||||
|  | @ -294,11 +368,13 @@ with open(outfile, "w") as f: | ||||||
| 
 | 
 | ||||||
|     print("  {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f) |     print("  {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f) | ||||||
|     print("      module(module), sigmap(module) {", file=f) |     print("      module(module), sigmap(module) {", file=f) | ||||||
|     for s, t in sorted(udata_types.items()): |     for current_pattern in sorted(patterns.keys()): | ||||||
|         if t.endswith("*"): |         for s, t in sorted(udata_types[current_pattern].items()): | ||||||
|             print("    ud.{} = nullptr;".format(s), file=f) |             if t.endswith("*"): | ||||||
|         else: |                 print("    ud_{}.{} = nullptr;".format(current_pattern,s), file=f) | ||||||
|             print("    ud.{} = {}();".format(s, t), file=f) |             else: | ||||||
|  |                 print("    ud_{}.{} = {}();".format(current_pattern, s, t), file=f) | ||||||
|  |     current_pattern = None | ||||||
|     print("    for (auto cell : module->cells()) {", file=f) |     print("    for (auto cell : module->cells()) {", file=f) | ||||||
|     print("      for (auto &conn : cell->connections())", file=f) |     print("      for (auto &conn : cell->connections())", file=f) | ||||||
|     print("        add_siguser(conn.second, cell);", file=f) |     print("        add_siguser(conn.second, cell);", file=f) | ||||||
|  | @ -328,34 +404,52 @@ with open(outfile, "w") as f: | ||||||
|     print("  }", file=f) |     print("  }", file=f) | ||||||
|     print("", file=f) |     print("", file=f) | ||||||
| 
 | 
 | ||||||
|     print("  void run(std::function<void()> on_accept_f) {", file=f) |     for current_pattern in sorted(patterns.keys()): | ||||||
|     print("    on_accept = on_accept_f;", file=f) |         print("  void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f) | ||||||
|     print("    rollback = 0;", file=f) |         print("    on_accept = on_accept_f;", file=f) | ||||||
|     print("    blacklist_dirty = false;", file=f) |         print("    rollback = 0;", file=f) | ||||||
|     for s, t in sorted(state_types.items()): |         print("    blacklist_dirty = false;", file=f) | ||||||
|         if t.endswith("*"): |         for s, t in sorted(state_types[current_pattern].items()): | ||||||
|             print("    st.{} = nullptr;".format(s), file=f) |             if t.endswith("*"): | ||||||
|         else: |                 print("    st_{}.{} = nullptr;".format(current_pattern, s), file=f) | ||||||
|             print("    st.{} = {}();".format(s, t), file=f) |             else: | ||||||
|     print("    block_0();", file=f) |                 print("    st_{}.{} = {}();".format(current_pattern, s, t), file=f) | ||||||
|     print("  }", file=f) |         print("    block_{}();".format(patterns[current_pattern]), file=f) | ||||||
|     print("", file=f) |         print("  }", file=f) | ||||||
| 
 |         print("", file=f) | ||||||
|     print("  void run(std::function<void({}_pm&)> on_accept_f) {{".format(prefix), file=f) |         print("  void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f) | ||||||
|     print("    run([&](){on_accept_f(*this);});", file=f) |         print("    run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f) | ||||||
|     print("  }", file=f) |         print("  }", file=f) | ||||||
|     print("", file=f) |         print("", file=f) | ||||||
|  |         print("  void run_{}(std::function<void(state_{}_t&)> on_accept_f) {{".format(current_pattern, current_pattern), file=f) | ||||||
|  |         print("    run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f) | ||||||
|  |         print("  }", file=f) | ||||||
|  |         print("", file=f) | ||||||
|  |         print("  void run_{}() {{".format(current_pattern), file=f) | ||||||
|  |         print("    run_{}([](){{}});".format(current_pattern, current_pattern), file=f) | ||||||
|  |         print("  }", file=f) | ||||||
|  |         print("", file=f) | ||||||
|  |     current_pattern = None | ||||||
| 
 | 
 | ||||||
|     for index in range(len(blocks)): |     for index in range(len(blocks)): | ||||||
|         block = blocks[index] |         block = blocks[index] | ||||||
| 
 | 
 | ||||||
|         print("  void block_{}() {{".format(index), file=f) |         print("  void block_{}() {{".format(index), file=f) | ||||||
|  |         current_pattern = block["pattern"] | ||||||
|  | 
 | ||||||
|  |         if block["type"] == "final": | ||||||
|  |             print("    on_accept();", file=f) | ||||||
|  |             print("    check_blacklist_{}();".format(current_pattern), file=f) | ||||||
|  |             print("  }", file=f) | ||||||
|  |             if index+1 != len(blocks): | ||||||
|  |                 print("", file=f) | ||||||
|  |             continue | ||||||
| 
 | 
 | ||||||
|         const_st = set() |         const_st = set() | ||||||
|         nonconst_st = set() |         nonconst_st = set() | ||||||
|         restore_st = set() |         restore_st = set() | ||||||
| 
 | 
 | ||||||
|         for i in range(index): |         for i in range(patterns[current_pattern], index): | ||||||
|             if blocks[i]["type"] == "code": |             if blocks[i]["type"] == "code": | ||||||
|                 for s in blocks[i]["states"]: |                 for s in blocks[i]["states"]: | ||||||
|                     const_st.add(s) |                     const_st.add(s) | ||||||
|  | @ -378,27 +472,27 @@ with open(outfile, "w") as f: | ||||||
|             assert False |             assert False | ||||||
| 
 | 
 | ||||||
|         for s in sorted(const_st): |         for s in sorted(const_st): | ||||||
|             t = state_types[s] |             t = state_types[current_pattern][s] | ||||||
|             if t.endswith("*"): |             if t.endswith("*"): | ||||||
|                 print("    {} const &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) |                 print("    {} const &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) | ||||||
|             else: |             else: | ||||||
|                 print("    const {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) |                 print("    const {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) | ||||||
| 
 | 
 | ||||||
|         for s in sorted(nonconst_st): |         for s in sorted(nonconst_st): | ||||||
|             t = state_types[s] |             t = state_types[current_pattern][s] | ||||||
|             print("    {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) |             print("    {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) | ||||||
| 
 | 
 | ||||||
|         if len(restore_st): |         if len(restore_st): | ||||||
|             print("", file=f) |             print("", file=f) | ||||||
|             for s in sorted(restore_st): |             for s in sorted(restore_st): | ||||||
|                 t = state_types[s] |                 t = state_types[current_pattern][s] | ||||||
|                 print("    {} backup_{} = {};".format(t, s, s), file=f) |                 print("    {} backup_{} = {};".format(t, s, s), file=f) | ||||||
| 
 | 
 | ||||||
|         if block["type"] == "code": |         if block["type"] == "code": | ||||||
|             print("", file=f) |             print("", file=f) | ||||||
|             print("    do {", file=f) |             print("    do {", file=f) | ||||||
|             print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f) |             print("#define reject do {{ check_blacklist_{}(); goto rollback_label; }} while(0)".format(current_pattern), file=f) | ||||||
|             print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) |             print("#define accept do {{ on_accept(); check_blacklist_{}(); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f) | ||||||
|             print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) |             print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) | ||||||
| 
 | 
 | ||||||
|             for line in block["code"]: |             for line in block["code"]: | ||||||
|  | @ -417,11 +511,11 @@ with open(outfile, "w") as f: | ||||||
|             if len(restore_st) or len(nonconst_st): |             if len(restore_st) or len(nonconst_st): | ||||||
|                 print("", file=f) |                 print("", file=f) | ||||||
|                 for s in sorted(restore_st): |                 for s in sorted(restore_st): | ||||||
|                     t = state_types[s] |                     t = state_types[current_pattern][s] | ||||||
|                     print("    {} = backup_{};".format(s, s), file=f) |                     print("    {} = backup_{};".format(s, s), file=f) | ||||||
|                 for s in sorted(nonconst_st): |                 for s in sorted(nonconst_st): | ||||||
|                     if s not in restore_st: |                     if s not in restore_st: | ||||||
|                         t = state_types[s] |                         t = state_types[current_pattern][s] | ||||||
|                         if t.endswith("*"): |                         if t.endswith("*"): | ||||||
|                             print("    {} = nullptr;".format(s), file=f) |                             print("    {} = nullptr;".format(s), file=f) | ||||||
|                         else: |                         else: | ||||||
|  | @ -470,17 +564,12 @@ with open(outfile, "w") as f: | ||||||
|         else: |         else: | ||||||
|             assert False |             assert False | ||||||
| 
 | 
 | ||||||
| 
 |         current_pattern = None | ||||||
|         print("  }", file=f) |         print("  }", file=f) | ||||||
|         print("", file=f) |         print("", file=f) | ||||||
| 
 | 
 | ||||||
|     print("  void block_{}() {{".format(len(blocks)), file=f) |  | ||||||
|     print("    on_accept();", file=f) |  | ||||||
|     print("    check_blacklist();", file=f) |  | ||||||
|     print("  }", file=f) |  | ||||||
|     print("};", file=f) |     print("};", file=f) | ||||||
| 
 | 
 | ||||||
|     print("", file=f) |     if genhdr: | ||||||
|     print("YOSYS_NAMESPACE_END", file=f) |         print("", file=f) | ||||||
| 
 |         print("YOSYS_NAMESPACE_END", file=f) | ||||||
| # pp.pprint(blocks) |  | ||||||
|  |  | ||||||
|  | @ -508,7 +508,7 @@ struct ExposePass : public Pass { | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				for (auto &conn : module->connections_) | 				for (auto &conn : module->connections_) | ||||||
| 					conn.first = out_to_in_map(sigmap(conn.first)); | 					conn.first = out_to_in_map(conn.first); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (flag_cut) | 			if (flag_cut) | ||||||
|  |  | ||||||
|  | @ -1169,6 +1169,7 @@ struct SatPass : public Pass { | ||||||
| 			if (args[argidx] == "-tempinduct-def") { | 			if (args[argidx] == "-tempinduct-def") { | ||||||
| 				tempinduct = true; | 				tempinduct = true; | ||||||
| 				tempinduct_def = true; | 				tempinduct_def = true; | ||||||
|  | 				enable_undef = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			if (args[argidx] == "-tempinduct-baseonly") { | 			if (args[argidx] == "-tempinduct-baseonly") { | ||||||
|  |  | ||||||
|  | @ -330,20 +330,33 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) | ||||||
| std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) | std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) | ||||||
| { | { | ||||||
| 	std::string abc_sname = abc_name.substr(1); | 	std::string abc_sname = abc_name.substr(1); | ||||||
| 	if (abc_sname.substr(0, 5) == "ys__n") { | 	bool isnew = false; | ||||||
| 		bool inv = abc_sname.back() == 'v'; | 	if (abc_sname.substr(0, 4) == "new_") | ||||||
| 		if (inv) abc_sname.pop_back(); | 	{ | ||||||
|  | 		abc_sname.erase(0, 4); | ||||||
|  | 		isnew = true; | ||||||
|  | 	} | ||||||
|  | 	if (abc_sname.substr(0, 5) == "ys__n") | ||||||
|  | 	{ | ||||||
| 		abc_sname.erase(0, 5); | 		abc_sname.erase(0, 5); | ||||||
| 		if (abc_sname.find_last_not_of("012345689") == std::string::npos) { | 		if (std::isdigit(abc_sname.at(0))) | ||||||
|  | 		{ | ||||||
| 			int sid = std::stoi(abc_sname); | 			int sid = std::stoi(abc_sname); | ||||||
| 			for (auto sig : signal_list) { | 			size_t postfix_start = abc_sname.find_first_not_of("0123456789"); | ||||||
| 				if (sig.id == sid && sig.bit.wire != nullptr) { | 			std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : ""; | ||||||
|  | 
 | ||||||
|  | 			if (sid < GetSize(signal_list)) | ||||||
|  | 			{ | ||||||
|  | 				auto sig = signal_list.at(sid); | ||||||
|  | 				if (sig.bit.wire != nullptr) | ||||||
|  | 				{ | ||||||
| 					std::stringstream sstr; | 					std::stringstream sstr; | ||||||
| 					sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); | 					sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); | ||||||
| 					if (sig.bit.wire->width != 1) | 					if (sig.bit.wire->width != 1) | ||||||
| 						sstr << "[" << sig.bit.offset << "]"; | 						sstr << "[" << sig.bit.offset << "]"; | ||||||
| 					if (inv) | 					if (isnew) | ||||||
| 						sstr << "_inv"; | 						sstr << "_new"; | ||||||
|  | 					sstr << postfix; | ||||||
| 					if (orig_wire != nullptr) | 					if (orig_wire != nullptr) | ||||||
| 						*orig_wire = sig.bit.wire; | 						*orig_wire = sig.bit.wire; | ||||||
| 					return sstr.str(); | 					return sstr.str(); | ||||||
|  |  | ||||||
|  | @ -102,7 +102,8 @@ struct DffinitPass : public Pass { | ||||||
| 				if (wire->attributes.count("\\init")) { | 				if (wire->attributes.count("\\init")) { | ||||||
| 					Const value = wire->attributes.at("\\init"); | 					Const value = wire->attributes.at("\\init"); | ||||||
| 					for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) | 					for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) | ||||||
| 						init_bits[sigmap(SigBit(wire, i))] = value[i]; | 						if (value[i] != State::Sx) | ||||||
|  | 							init_bits[sigmap(SigBit(wire, i))] = value[i]; | ||||||
| 				} | 				} | ||||||
| 				if (wire->port_output) | 				if (wire->port_output) | ||||||
| 					for (auto bit : sigmap(wire)) | 					for (auto bit : sigmap(wire)) | ||||||
|  |  | ||||||
|  | @ -178,7 +178,17 @@ struct ShregmapTechXilinx7 : ShregmapTech | ||||||
| 
 | 
 | ||||||
| 		// Only map if $shiftx exclusively covers the shift register
 | 		// Only map if $shiftx exclusively covers the shift register
 | ||||||
| 		if (shiftx->type == "$shiftx") { | 		if (shiftx->type == "$shiftx") { | ||||||
| 			if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) | 			if (GetSize(taps) > shiftx->getParam("\\A_WIDTH").as_int()) | ||||||
|  | 				return false; | ||||||
|  | 			// Due to padding the most significant bits of A may be 1'bx,
 | ||||||
|  | 			//   and if so, discount them
 | ||||||
|  | 			if (GetSize(taps) < shiftx->getParam("\\A_WIDTH").as_int()) { | ||||||
|  | 				const SigSpec A = shiftx->getPort("\\A"); | ||||||
|  | 				const int A_width = shiftx->getParam("\\A_WIDTH").as_int(); | ||||||
|  | 				for (int i = GetSize(taps); i < A_width; ++i) | ||||||
|  | 					if (A[i] != RTLIL::Sx) return false; | ||||||
|  | 			} | ||||||
|  | 			else if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) | ||||||
| 				return false; | 				return false; | ||||||
| 		} | 		} | ||||||
| 		else if (shiftx->type == "$mux") { | 		else if (shiftx->type == "$mux") { | ||||||
|  |  | ||||||
|  | @ -201,6 +201,8 @@ struct SynthPass : public ScriptPass | ||||||
| 			run("check"); | 			run("check"); | ||||||
| 			run("opt"); | 			run("opt"); | ||||||
| 			run("wreduce"); | 			run("wreduce"); | ||||||
|  | 			run("peepopt"); | ||||||
|  | 			run("opt_clean"); | ||||||
| 			if (help_mode) | 			if (help_mode) | ||||||
| 				run("techmap -map +/cmp2lut.v", " (if -lut)"); | 				run("techmap -map +/cmp2lut.v", " (if -lut)"); | ||||||
| 			else | 			else | ||||||
|  |  | ||||||
|  | @ -241,6 +241,8 @@ struct SynthIce40Pass : public ScriptPass | ||||||
| 			run("check"); | 			run("check"); | ||||||
| 			run("opt"); | 			run("opt"); | ||||||
| 			run("wreduce"); | 			run("wreduce"); | ||||||
|  | 			run("peepopt"); | ||||||
|  | 			run("opt_clean"); | ||||||
| 			run("share"); | 			run("share"); | ||||||
| 			run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); | 			run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); | ||||||
| 			run("opt_expr"); | 			run("opt_expr"); | ||||||
|  |  | ||||||
|  | @ -17,6 +17,16 @@ | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | // Convert negative-polarity reset to positive-polarity | ||||||
|  | (* techmap_celltype = "$_DFF_NN0_" *) | ||||||
|  | module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule | ||||||
|  | (* techmap_celltype = "$_DFF_PN0_" *) | ||||||
|  | module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule | ||||||
|  | (* techmap_celltype = "$_DFF_NN1_" *) | ||||||
|  | module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1   _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule | ||||||
|  | (* techmap_celltype = "$_DFF_PN1_" *) | ||||||
|  | module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1   _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule | ||||||
|  | 
 | ||||||
| module \$__SHREG_ (input C, input D, input E, output Q); | module \$__SHREG_ (input C, input D, input E, output Q); | ||||||
|   parameter DEPTH = 0; |   parameter DEPTH = 0; | ||||||
|   parameter [DEPTH-1:0] INIT = 0; |   parameter [DEPTH-1:0] INIT = 0; | ||||||
|  |  | ||||||
|  | @ -22,26 +22,21 @@ | ||||||
| 
 | 
 | ||||||
| `ifndef _NO_FFS | `ifndef _NO_FFS | ||||||
| 
 | 
 | ||||||
| `ifndef _NO_POS_SR |  | ||||||
| module  \$_DFF_N_   (input D, C, output Q);    FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule | module  \$_DFF_N_   (input D, C, output Q);    FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule | ||||||
| module  \$_DFF_P_   (input D, C, output Q);    FDRE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule | module  \$_DFF_P_   (input D, C, output Q);    FDRE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule | ||||||
| 
 | 
 | ||||||
| module  \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E),    .R(1'b0)); endmodule | module  \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E),    .R(1'b0)); endmodule | ||||||
| module  \$_DFFE_PP_ (input D, C, E, output Q); FDRE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E),    .R(1'b0)); endmodule | module  \$_DFFE_PP_ (input D, C, E, output Q); FDRE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E),    .R(1'b0)); endmodule | ||||||
| 
 | 
 | ||||||
|  | module  \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule | ||||||
| module  \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule | module  \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule | ||||||
|  | module  \$_DFF_PN0_ (input D, C, R, output Q); FDCE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule | ||||||
| module  \$_DFF_PP0_ (input D, C, R, output Q); FDCE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule | module  \$_DFF_PP0_ (input D, C, R, output Q); FDCE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule | ||||||
| 
 | 
 | ||||||
|  | module  \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule | ||||||
| module  \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule | module  \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule | ||||||
|  | module  \$_DFF_PN1_ (input D, C, R, output Q); FDPE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule | ||||||
| module  \$_DFF_PP1_ (input D, C, R, output Q); FDPE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule | module  \$_DFF_PP1_ (input D, C, R, output Q); FDPE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule | ||||||
| `endif |  | ||||||
| 
 |  | ||||||
| module  \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_         _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule |  | ||||||
| module  \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_         _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule |  | ||||||
| 
 |  | ||||||
| module  \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1          _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule |  | ||||||
| module  \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1          _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule |  | ||||||
| `endif |  | ||||||
| 
 | 
 | ||||||
| `endif | `endif | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -205,45 +205,41 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (check_label("fine")) { | 		if (check_label("fine")) { | ||||||
| 			run("opt -fast"); | 			// shregmap -tech xilinx can cope with $shiftx and $mux
 | ||||||
|  | 			//   cells for identifiying variable-length shift registers,
 | ||||||
|  | 			//   so attempt to convert $pmux-es to the former
 | ||||||
|  | 			if (!nosrl || help_mode) | ||||||
|  | 				run("pmux2shiftx", "(skip if '-nosrl')"); | ||||||
|  | 
 | ||||||
|  | 			run("opt -fast -full"); | ||||||
| 			run("memory_map"); | 			run("memory_map"); | ||||||
| 			run("dffsr2dff"); | 			run("dffsr2dff"); | ||||||
| 			run("dff2dffe"); | 			run("dff2dffe"); | ||||||
|  | 			run("opt -full"); | ||||||
| 
 | 
 | ||||||
| 			if (!vpr || help_mode) | 			if (!vpr || help_mode) | ||||||
| 				run("techmap -map +/xilinx/arith_map.v"); | 				run("techmap -map +/xilinx/arith_map.v"); | ||||||
| 			else | 			else | ||||||
| 				run("techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); | 				run("techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); | ||||||
| 
 | 
 | ||||||
| 			run("hierarchy -check"); |  | ||||||
| 			run("opt -fast"); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (check_label("map_cells")) |  | ||||||
| 		{ |  | ||||||
| 			if (!nosrl || help_mode) { | 			if (!nosrl || help_mode) { | ||||||
| 				// shregmap operates on bit-level flops, not word-level,
 | 				// shregmap operates on bit-level flops, not word-level,
 | ||||||
| 				//   so break those down here
 | 				//   so break those down here
 | ||||||
| 				run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')"); | 				run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')"); | ||||||
| 				// shregmap -tech xilinx can cope with $shiftx and $mux
 |  | ||||||
| 				//   cells for identifiying variable-length shift registers,
 |  | ||||||
| 				//   so attempt to convert $pmux-es to the former
 |  | ||||||
| 				run("pmux2shiftx", "(skip if '-nosrl')"); |  | ||||||
| 				// pmux2shiftx can leave behind a $pmux with a single entry
 |  | ||||||
| 				//   -- need this to clean that up before shregmap
 |  | ||||||
| 				run("opt_expr -mux_undef", "(skip if '-nosrl')"); |  | ||||||
| 				// shregmap with '-tech xilinx' infers variable length shift regs
 | 				// shregmap with '-tech xilinx' infers variable length shift regs
 | ||||||
| 				run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')"); | 				run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')"); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			run("techmap -map +/xilinx/cells_map.v"); | 			run("techmap"); | ||||||
|  | 			run("opt -fast"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (check_label("map_cells")) { | ||||||
|  | 			run("techmap -map +/techmap.v -map +/xilinx/cells_map.v"); | ||||||
| 			run("clean"); | 			run("clean"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (check_label("map_luts")) | 		if (check_label("map_luts")) { | ||||||
| 		{ |  | ||||||
| 			run("opt -full"); |  | ||||||
| 			run("techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v"); |  | ||||||
| 			if (help_mode) | 			if (help_mode) | ||||||
| 				run("abc -luts 2:2,3,6:5,10,20 [-dff]"); | 				run("abc -luts 2:2,3,6:5,10,20 [-dff]"); | ||||||
| 			else | 			else | ||||||
|  | @ -259,21 +255,18 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 			run("clean"); | 			run("clean"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (check_label("check")) | 		if (check_label("check")) { | ||||||
| 		{ |  | ||||||
| 			run("hierarchy -check"); | 			run("hierarchy -check"); | ||||||
| 			run("stat"); | 			run("stat"); | ||||||
| 			run("check -noinit"); | 			run("check -noinit"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (check_label("edif")) | 		if (check_label("edif")) { | ||||||
| 		{ |  | ||||||
| 			if (!edif_file.empty() || help_mode) | 			if (!edif_file.empty() || help_mode) | ||||||
| 				run(stringf("write_edif -pvector bra %s", edif_file.c_str())); | 				run(stringf("write_edif -pvector bra %s", edif_file.c_str())); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (check_label("blif")) | 		if (check_label("blif")) { | ||||||
| 		{ |  | ||||||
| 			if (!blif_file.empty() || help_mode) | 			if (!blif_file.empty() || help_mode) | ||||||
| 				run(stringf("write_blif %s", edif_file.c_str())); | 				run(stringf("write_blif %s", edif_file.c_str())); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								tests/memories/firrtl_938.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/memories/firrtl_938.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | module top | ||||||
|  | ( | ||||||
|  | 	input [7:0] data_a, | ||||||
|  | 	input [6:1] addr_a, | ||||||
|  | 	input we_a, clk, | ||||||
|  | 	output reg [7:0] q_a | ||||||
|  | ); | ||||||
|  | 	// Declare the RAM variable | ||||||
|  | 	reg [7:0] ram[63:0]; | ||||||
|  | 
 | ||||||
|  | 	// Port A | ||||||
|  | 	always @ (posedge clk) | ||||||
|  | 	begin | ||||||
|  | 		if (we_a) | ||||||
|  | 		begin | ||||||
|  | 			ram[addr_a] <= data_a; | ||||||
|  | 			q_a <= data_a; | ||||||
|  | 		end | ||||||
|  | 			q_a <= ram[addr_a]; | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | endmodule | ||||||
|  | @ -92,3 +92,25 @@ module mem2reg_test5(input ctrl, output out); | ||||||
| 	assign out = bar[foo[0]]; | 	assign out = bar[foo[0]]; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | // ------------------------------------------------------ | ||||||
|  | 
 | ||||||
|  | module mem2reg_test6 (din, dout); | ||||||
|  |         input   wire    [3:0] din; | ||||||
|  |         output  reg     [3:0] dout; | ||||||
|  | 
 | ||||||
|  |         reg [1:0] din_array  [1:0]; | ||||||
|  |         reg [1:0] dout_array [1:0]; | ||||||
|  | 
 | ||||||
|  |         always @* begin | ||||||
|  | 		din_array[0] = din[0 +: 2]; | ||||||
|  | 		din_array[1] = din[2 +: 2]; | ||||||
|  | 
 | ||||||
|  | 		dout_array[0] = din_array[0]; | ||||||
|  | 		dout_array[1] = din_array[1]; | ||||||
|  | 
 | ||||||
|  | 		{dout_array[0][1], dout_array[0][0]} = dout_array[0][0] + dout_array[1][0]; | ||||||
|  | 
 | ||||||
|  | 		dout[0 +: 2] = dout_array[0]; | ||||||
|  | 		dout[2 +: 2] = dout_array[1]; | ||||||
|  |         end | ||||||
|  | endmodule | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								tests/simple/peepopt.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/simple/peepopt.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | module peepopt_shiftmul_0 #(parameter N=3, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output [W-1:0] o); | ||||||
|  | assign o = i[s*W+:W]; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module peepopt_muldiv_0(input [1:0] i, output [1:0] o); | ||||||
|  | wire [3:0] t; | ||||||
|  | assign t = i * 3; | ||||||
|  | assign o = t / 3; | ||||||
|  | endmodule | ||||||
|  | @ -16,6 +16,7 @@ operators.v	$pow | ||||||
| partsel.v	drops modules | partsel.v	drops modules | ||||||
| process.v	drops modules | process.v	drops modules | ||||||
| realexpr.v	drops modules | realexpr.v	drops modules | ||||||
|  | retime.v	Initial value (11110101) for (retime_test.ff) not supported | ||||||
| scopes.v	original verilog issues ( -x where x isn't declared signed) | scopes.v	original verilog issues ( -x where x isn't declared signed) | ||||||
| sincos.v	$adff | sincos.v	$adff | ||||||
| specify.v	no code (empty module generates error | specify.v	no code (empty module generates error | ||||||
|  |  | ||||||
|  | @ -11,13 +11,13 @@ echo "" > $STDERRFILE | ||||||
| 
 | 
 | ||||||
| echo -n "Test: ${TESTNAME} -> " | echo -n "Test: ${TESTNAME} -> " | ||||||
| 
 | 
 | ||||||
| $PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE >> $STDERRFILE | set -e | ||||||
| $PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE >> $STDERRFILE | 
 | ||||||
|  | $PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE 2>> $STDERRFILE | ||||||
|  | $PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE 2>> $STDERRFILE | ||||||
| 
 | 
 | ||||||
| rm -f a.out reference_result.txt dut_result.txt | rm -f a.out reference_result.txt dut_result.txt | ||||||
| 
 | 
 | ||||||
| set -e |  | ||||||
| 
 |  | ||||||
| iverilog -g2012 ${TESTNAME}_syn.v | iverilog -g2012 ${TESTNAME}_syn.v | ||||||
| iverilog -g2012 ${TESTNAME}_ref_syn.v | iverilog -g2012 ${TESTNAME}_ref_syn.v | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -147,7 +147,8 @@ do | ||||||
| 		fi | 		fi | ||||||
| 		if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi | 		if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi | ||||||
| 		compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \ | 		compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \ | ||||||
| 					"$toolsdir"/../../techlibs/common/simlib.v | 					"$toolsdir"/../../techlibs/common/simlib.v \ | ||||||
|  | 					"$toolsdir"/../../techlibs/common/simcells.v | ||||||
| 		if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi | 		if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi | ||||||
| 
 | 
 | ||||||
| 		test_count=0 | 		test_count=0 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue