diff options
| author | Eddie Hung <eddie@fpgeh.com> | 2019-05-01 18:09:38 -0700 | 
|---|---|---|
| committer | Eddie Hung <eddie@fpgeh.com> | 2019-05-01 18:09:38 -0700 | 
| commit | 31ff0d8ef529a1ddfa37e4b68017e4e433399da7 (patch) | |
| tree | 921a3a801a4e7bc9d8998b0aa7f21506db7881e6 | |
| parent | e97178a888cebc6acacb8f8f2c68d4f9743a9284 (diff) | |
| parent | f86d153cef724af9d30e4139783a7e14d7ba0a19 (diff) | |
| download | yosys-31ff0d8ef529a1ddfa37e4b68017e4e433399da7.tar.gz yosys-31ff0d8ef529a1ddfa37e4b68017e4e433399da7.tar.bz2 yosys-31ff0d8ef529a1ddfa37e4b68017e4e433399da7.zip  | |
Merge remote-tracking branch 'origin/master' into eddie/synth_xilinx_fine
| -rw-r--r-- | Makefile | 8 | ||||
| -rw-r--r-- | backends/firrtl/firrtl.cc | 45 | ||||
| -rw-r--r-- | frontends/ast/simplify.cc | 9 | ||||
| -rw-r--r-- | frontends/verilog/verilog_frontend.cc | 4 | ||||
| -rw-r--r-- | kernel/driver.cc | 4 | ||||
| -rw-r--r-- | kernel/rtlil.cc | 2 | ||||
| -rw-r--r-- | kernel/yosys.cc | 14 | ||||
| -rw-r--r-- | kernel/yosys.h | 1 | ||||
| -rw-r--r-- | misc/__init__.py (renamed from __init__.py) | 0 | ||||
| -rw-r--r-- | misc/py_wrap_generator.py (renamed from py_wrap_generator.py) | 0 | ||||
| -rw-r--r-- | passes/cmds/qwp.cc | 2 | ||||
| -rw-r--r-- | passes/equiv/equiv_opt.cc | 19 | ||||
| -rw-r--r-- | passes/opt/opt_clean.cc | 13 | ||||
| -rw-r--r-- | passes/opt/opt_expr.cc | 43 | ||||
| -rw-r--r-- | passes/opt/wreduce.cc | 2 | ||||
| -rw-r--r-- | passes/sat/sat.cc | 1 | ||||
| -rw-r--r-- | passes/techmap/shregmap.cc | 12 | ||||
| -rw-r--r-- | techlibs/ecp5/synth_ecp5.cc | 2 | ||||
| -rw-r--r-- | techlibs/ice40/synth_ice40.cc | 10 | ||||
| -rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 262 | ||||
| -rw-r--r-- | tests/memories/firrtl_938.v | 22 | ||||
| -rw-r--r-- | tests/simple/xfirrtl | 1 | 
22 files changed, 286 insertions, 190 deletions
@@ -294,7 +294,7 @@ endif  PY_WRAPPER_FILE = kernel/python_wrappers  OBJS += $(PY_WRAPPER_FILE).o  PY_GEN_SCRIPT= py_wrap_generator -PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()") +PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()")  endif  ifeq ($(ENABLE_READLINE),1) @@ -550,9 +550,9 @@ libyosys.so: $(filter-out kernel/driver.o,$(OBJS))  	$(Q) mkdir -p $(dir $@)  	$(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(LD) -x c++ -o $@ -E -P - -$(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES) +$(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES)  	$(Q) mkdir -p $(dir $@) -	$(P) python$(PYTHON_VERSION) -c "import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")" +	$(P) python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")"  %.o: %.cpp  	$(Q) mkdir -p $(dir $@) @@ -685,7 +685,7 @@ ifeq ($(ENABLE_LIBYOSYS),1)  ifeq ($(ENABLE_PYOSYS),1)  	$(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys  	$(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys -	$(INSTALL_SUDO) cp __init__.py $(PYTHON_DESTDIR)/pyosys +	$(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys  endif  endif diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index ed6e9f8ee..a8a1bb078 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -164,6 +164,7 @@ struct FirrtlWorker  	};  	/* Memories defined within this module. */  	 struct memory { +		 Cell *pCell;					// for error reporting  		 string name;					// memory name  		 int abits;						// number of address bits  		 int size;						// size (in units) of the memory @@ -174,8 +175,37 @@ struct FirrtlWorker  		 vector<write_port> write_ports;  		 std::string init_file;  		 std::string init_file_srcFileSpec; -		 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("") {} -		 memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} +		 string srcLine; +		 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("") { +			// Provide defaults for abits or size if one (but not the other) is specified. +			if (this->abits == 0 && this->size != 0) { +				this->abits = ceil_log2(this->size); +			} else if (this->abits != 0 && this->size == 0) { +				this->size = 1 << this->abits; +			} +			// Sanity-check this construction. +			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);  		 } @@ -604,7 +634,7 @@ struct FirrtlWorker  				int abits = cell->parameters.at("\\ABITS").as_int();  				int width = cell->parameters.at("\\WIDTH").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 wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); @@ -681,6 +711,8 @@ struct FirrtlWorker  			{  				std::string cell_type = fid(cell->type);  				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;  				if (cell->type == "$meminit" ) {  					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_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);  					int portNum = 0;  					bool transparency = false; @@ -890,7 +927,7 @@ struct FirrtlWorker  		// If we have any memory definitions, output them.  		for (auto kv : memories) { -			memory m = kv.second; +			memory &m = kv.second;  			f << stringf("    mem %s:\n", m.name.c_str());  			f << stringf("      data-type => UInt<%d>\n", m.width);  			f << stringf("      depth => %d\n", m.size); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 3e453bd7f..4d4b9dfe1 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1172,6 +1172,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			varbuf->children[0] = buf;  		} +#if 0 +		if (type == AST_FOR) { +			AstNode *buf = next_ast->clone(); +			delete buf->children[1]; +			buf->children[1] = varbuf->children[0]->clone(); +			current_block->children.insert(current_block->children.begin() + current_block_idx++, buf); +		} +#endif +  		current_scope[varbuf->str] = backup_scope_varbuf;  		delete varbuf;  		delete_children(); diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index ed6ce2ecb..9e624d355 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -242,8 +242,6 @@ struct VerilogFrontend : public Frontend {  		nowb_mode = false;  		default_nettype_wire = true; -		log_header(design, "Executing Verilog-2005 frontend.\n"); -  		args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());  		size_t argidx; @@ -415,6 +413,8 @@ struct VerilogFrontend : public Frontend {  		}  		extra_args(f, filename, args, argidx); +		log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str()); +  		log("Parsing %s%s input from `%s' to AST representation.\n",  				formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str()); diff --git a/kernel/driver.cc b/kernel/driver.cc index 1bc7a5935..f273057dd 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -529,13 +529,13 @@ int main(int argc, char **argv)  			log_error("Can't open dependencies file for writing: %s\n", strerror(errno));  		bool first = true;  		for (auto fn : yosys_output_files) { -			fprintf(f, "%s%s", first ? "" : " ", fn.c_str()); +			fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces(fn).c_str());  			first = false;  		}  		fprintf(f, ":");  		for (auto fn : yosys_input_files) {  			if (yosys_output_files.count(fn) == 0) -				fprintf(f, " %s", fn.c_str()); +				fprintf(f, " %s", escape_filename_spaces(fn).c_str());  		}  		fprintf(f, "\n");  	} diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 7e1159cac..dd6817873 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3456,7 +3456,7 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const  	pack();  	other.pack(); -	if (chunks_.size() != chunks_.size()) +	if (chunks_.size() != other.chunks_.size())  		return false;  	updhash(); diff --git a/kernel/yosys.cc b/kernel/yosys.cc index a12355f1d..20d972150 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -482,6 +482,20 @@ void remove_directory(std::string dirname)  #endif  } +std::string escape_filename_spaces(const std::string& filename) +{ +	std::string out; +	out.reserve(filename.size()); +	for (auto c : filename) +	{ +		if (c == ' ') +			out += "\\ "; +		else +			out.push_back(c); +	} +	return out; +} +  int GetSize(RTLIL::Wire *wire)  {  	return wire->width; diff --git a/kernel/yosys.h b/kernel/yosys.h index 2cf6188b4..82eb069ab 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -257,6 +257,7 @@ std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX");  bool check_file_exists(std::string filename, bool is_exec = false);  bool is_absolute_path(std::string filename);  void remove_directory(std::string dirname); +std::string escape_filename_spaces(const std::string& filename);  template<typename T> int GetSize(const T &obj) { return obj.size(); }  int GetSize(RTLIL::Wire *wire); diff --git a/__init__.py b/misc/__init__.py index 330fd6d86..330fd6d86 100644 --- a/__init__.py +++ b/misc/__init__.py diff --git a/py_wrap_generator.py b/misc/py_wrap_generator.py index 09f934040..09f934040 100644 --- a/py_wrap_generator.py +++ b/misc/py_wrap_generator.py diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc index 1c64a7b77..adbe89e31 100644 --- a/passes/cmds/qwp.cc +++ b/passes/cmds/qwp.cc @@ -291,7 +291,7 @@ struct QwpWorker  		// gaussian elimination  		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);  			// find best row diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc index e5dda9c24..3596dfd7b 100644 --- a/passes/equiv/equiv_opt.cc +++ b/passes/equiv/equiv_opt.cc @@ -44,7 +44,10 @@ struct EquivOptPass:public ScriptPass  		log("        useful for handling architecture-specific primitives.\n");  		log("\n");  		log("    -assert\n"); -		log("        produce an error if the circuits are not equivalent\n"); +		log("        produce an error if the circuits are not equivalent.\n"); +		log("\n"); +		log("    -undef\n"); +		log("        enable modelling of undef states during equiv_induct.\n");  		log("\n");  		log("The following commands are executed by this verification command:\n");  		help_script(); @@ -52,13 +55,14 @@ struct EquivOptPass:public ScriptPass  	}  	std::string command, techmap_opts; -	bool assert; +	bool assert, undef;  	void clear_flags() YS_OVERRIDE  	{  		command = "";  		techmap_opts = "";  		assert = false; +		undef = false;  	}  	void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE @@ -84,6 +88,10 @@ struct EquivOptPass:public ScriptPass  				assert = true;  				continue;  			} +			if (args[argidx] == "-undef") { +				undef = true; +				continue; +			}  			break;  		} @@ -139,7 +147,12 @@ struct EquivOptPass:public ScriptPass  		if (check_label("prove")) {  			run("equiv_make gold gate equiv"); -			run("equiv_induct equiv"); +			if (help_mode) +				run("equiv_induct [-undef] equiv"); +			else if (undef) +				run("equiv_induct -undef equiv"); +			else +				run("equiv_induct equiv");  			if (help_mode)  				run("equiv_status [-assert] equiv");  			else if (assert) diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index c38e9df5e..5d95c4f1a 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -281,13 +281,26 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos  				maybe_del_wires.push_back(wire);  			} else {  				log_assert(GetSize(s1) == GetSize(s2)); +				Const initval; +				if (wire->attributes.count("\\init")) +					initval = wire->attributes.at("\\init"); +				if (GetSize(initval) != GetSize(wire)) +					initval.bits.resize(GetSize(wire), State::Sx);  				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); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index af6d352af..b445afdc8 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -39,6 +39,9 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)  	SigPool used_signals;  	SigPool all_signals; +	dict<SigBit, pair<Wire*, State>> initbits; +	pool<Wire*> revisit_initwires; +  	for (auto cell : module->cells())  	for (auto &conn : cell->connections()) {  		if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first)) @@ -48,6 +51,14 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)  	}  	for (auto wire : module->wires()) { +		if (wire->attributes.count("\\init")) { +			SigSpec sig = sigmap(wire); +			Const initval = wire->attributes.at("\\init"); +			for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) { +				if (initval[i] == State::S0 || initval[i] == State::S1) +					initbits[sig[i]] = make_pair(wire, initval[i]); +			} +		}  		if (wire->port_input)  			driven_signals.add(sigmap(wire));  		if (wire->port_output) @@ -67,10 +78,38 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)  		if (sig.size() == 0)  			continue; -		log_debug("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); -		module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width))); +		Const val(RTLIL::State::Sx, GetSize(sig)); +		for (int i = 0; i < GetSize(sig); i++) { +			SigBit bit = sigmap(sig[i]); +			auto cursor = initbits.find(bit); +			if (cursor != initbits.end()) { +				revisit_initwires.insert(cursor->second.first); +				val[i] = cursor->second.second; +			} +		} + +		log_debug("Setting undriven signal in %s to constant: %s = %s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(val)); +		module->connect(sig, val);  		did_something = true;  	} + +	if (!revisit_initwires.empty()) +	{ +		SigMap sm2(module); + +		for (auto wire : revisit_initwires) { +			SigSpec sig = sm2(wire); +			Const initval = wire->attributes.at("\\init"); +			for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) { +				if (SigBit(initval[i]) == sig[i]) +					initval[i] = State::Sx; +			} +			if (initval.is_fully_undef()) +				wire->attributes.erase("\\init"); +			else +				wire->attributes["\\init"] = initval; +		} +	}  }  void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 68e077cf9..41de8aad1 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -180,6 +180,8 @@ struct WreduceWorker  			}  			auto info = mi.query(sig_q[i]); +			if (info == nullptr) +				return;  			if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {  				remove_init_bits.insert(sig_q[i]);  				sig_d.remove(i); diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index 695a03e15..cbba738f0 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -1169,6 +1169,7 @@ struct SatPass : public Pass {  			if (args[argidx] == "-tempinduct-def") {  				tempinduct = true;  				tempinduct_def = true; +				enable_undef = true;  				continue;  			}  			if (args[argidx] == "-tempinduct-baseonly") { diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index a541b33be..75eedfbcc 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -178,7 +178,17 @@ struct ShregmapTechXilinx7 : ShregmapTech  		// Only map if $shiftx exclusively covers the shift register  		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;  		}  		else if (shiftx->type == "$mux") { diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 4b889d672..c6e12248e 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -253,7 +253,7 @@ struct SynthEcp5Pass : public ScriptPass  			if (!nodffe)  				run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");  			run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); -			run("opt_expr -mux_undef"); +			run("opt_expr -undriven -mux_undef");  			run("simplemap");  			run("ecp5_ffinit");  		} diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 8899bfcc4..5de33110a 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -225,11 +225,13 @@ struct SynthIce40Pass : public ScriptPass  			run("proc");  		} -		if (flatten && check_label("flatten", "(unless -noflatten)")) +		if (check_label("flatten", "(unless -noflatten)"))  		{ -			run("flatten"); -			run("tribuf -logic"); -			run("deminout"); +			if (flatten) { +				run("flatten"); +				run("tribuf -logic"); +				run("deminout"); +			}  		}  		if (check_label("coarse")) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index ba9efc658..dbafec301 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -25,18 +25,9 @@  USING_YOSYS_NAMESPACE  PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +struct SynthXilinxPass : public ScriptPass  { -	if (label == run_from) -		active = true; -	if (label == run_to) -		active = false; -	return active; -} - -struct SynthXilinxPass : public Pass -{ -	SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { } +	SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }  	void help() YS_OVERRIDE  	{ @@ -85,81 +76,30 @@ struct SynthXilinxPass : public Pass  		log("\n");  		log("\n");  		log("The following commands are executed by this synthesis command:\n"); +		help_script();  		log("\n"); -		log("    begin:\n"); -		log("        read_verilog -lib +/xilinx/cells_sim.v\n"); -		log("        read_verilog -lib +/xilinx/cells_xtra.v\n"); -		log("        read_verilog -lib +/xilinx/brams_bb.v\n"); -		log("        hierarchy -check -top <top>\n"); -		log("\n"); -		log("    flatten:     (only if -flatten)\n"); -		log("        proc\n"); -		log("        flatten\n"); -		log("\n"); -		log("    coarse:\n"); -		log("        synth -run coarse\n"); -		log("\n"); -		log("    bram: (only executed when '-nobram' is not given)\n"); -		log("        memory_bram -rules +/xilinx/brams.txt\n"); -		log("        techmap -map +/xilinx/brams_map.v\n"); -		log("\n"); -		log("    dram: (only executed when '-nodram' is not given)\n"); -		log("        memory_bram -rules +/xilinx/drams.txt\n"); -		log("        techmap -map +/xilinx/drams_map.v\n"); -		log("\n"); -		log("    fine:\n"); -		log("        opt -fast -full\n"); -		log("        memory_map\n"); -		log("        dffsr2dff\n"); -		log("        dff2dffe\n"); -		log("        techmap -map +/xilinx/arith_map.v\n"); -		log("        opt -full\n"); -		log("        simplemap t:$dff t:$dffe (without '-nosrl' only)\n"); -		log("        pmux2shiftx (without '-nosrl' only)\n"); -		log("        opt_expr -mux_undef (without '-nosrl' only)\n"); -		log("        shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); -		log("        opt -fast\n"); -		log("        techmap\n"); -		log("        opt -fast\n"); -		log("\n"); -		log("    map_cells:\n"); -		log("        techmap -map +/xilinx/cells_map.v\n"); -		log("        clean\n"); -		log("\n"); -		log("    map_luts:\n"); -		log("        techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\n"); -		log("        abc -luts 2:2,3,6:5,10,20 [-dff]\n"); -		log("        clean\n"); -		log("        shregmap -minlen 3 -init -params -enpol any_or_none (without '-nosrl' only)\n"); -		log("        techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); -		log("        dffinit -ff FDRE   Q INIT -ff FDCE   Q INIT -ff FDPE   Q INIT -ff FDSE   Q INIT \\\n"); -		log("                -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); -		log("        clean\n"); -		log("\n"); -		log("    check:\n"); -		log("        hierarchy -check\n"); -		log("        stat\n"); -		log("        check -noinit\n"); -		log("\n"); -		log("    edif:     (only if -edif)\n"); -		log("        write_edif <file-name>\n"); -		log("\n"); -		log("    blif:     (only if -blif)\n"); -		log("        write_blif <file-name>\n"); -		log("\n");  	} + +	std::string top_opt, edif_file, blif_file; +	bool flatten, retime, vpr, nobram, nodram, nosrl; + +	void clear_flags() YS_OVERRIDE +	{ +		top_opt = "-auto-top"; +		edif_file.clear(); +		blif_file.clear(); +		flatten = false; +		retime = false; +		vpr = false; +		nobram = false; +		nodram = false; +		nosrl = false; +	} +  	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE  	{ -		std::string top_opt = "-auto-top"; -		std::string edif_file; -		std::string blif_file;  		std::string run_from, run_to; -		bool flatten = false; -		bool retime = false; -		bool vpr = false; -		bool nobram = false; -		bool nodram = false; -		bool nosrl = false; +		clear_flags();  		size_t argidx;  		for (argidx = 1; argidx < args.size(); argidx++) @@ -215,130 +155,122 @@ struct SynthXilinxPass : public Pass  		if (!design->full_selection())  			log_cmd_error("This command only operates on fully selected designs!\n"); -		bool active = run_from.empty(); -  		log_header(design, "Executing SYNTH_XILINX pass.\n");  		log_push(); -		if (check_label(active, run_from, run_to, "begin")) -		{ -			if (vpr) { -				Pass::call(design, "read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v"); -			} else { -				Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v"); -			} +		run_script(design, run_from, run_to); + +		log_pop(); +	} + +	void script() YS_OVERRIDE +	{ +		if (check_label("begin")) { +			if (vpr) +				run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v"); +			else +				run("read_verilog -lib +/xilinx/cells_sim.v"); -			Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v"); +			run("read_verilog -lib +/xilinx/cells_xtra.v"); -			if (!nobram) { -				Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); -			} +			if (!nobram || help_mode) +				run("read_verilog -lib +/xilinx/brams_bb.v", "(skip if '-nobram')"); -			Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); +			run(stringf("hierarchy -check %s", top_opt.c_str()));  		} -		if (flatten && check_label(active, run_from, run_to, "flatten")) -		{ -			Pass::call(design, "proc"); -			Pass::call(design, "flatten"); +		if (check_label("flatten", "(with '-flatten' only)")) { +			if (flatten || help_mode) { +				run("proc"); +				run("flatten"); +			}  		} -		if (check_label(active, run_from, run_to, "coarse")) -		{ -			Pass::call(design, "synth -run coarse"); +		if (check_label("coarse")) { +			run("synth -run coarse");  		} -		if (check_label(active, run_from, run_to, "bram")) -		{ -			if (!nobram) { -				Pass::call(design, "memory_bram -rules +/xilinx/brams.txt"); -				Pass::call(design, "techmap -map +/xilinx/brams_map.v"); +		if (check_label("bram", "(skip if '-nobram')")) { +			if (!nobram || help_mode) { +				run("memory_bram -rules +/xilinx/brams.txt"); +				run("techmap -map +/xilinx/brams_map.v");  			}  		} -		if (check_label(active, run_from, run_to, "dram")) -		{ -			if (!nodram) { -				Pass::call(design, "memory_bram -rules +/xilinx/drams.txt"); -				Pass::call(design, "techmap -map +/xilinx/drams_map.v"); +		if (check_label("dram", "(skip if '-nodram')")) { +			if (!nodram || help_mode) { +				run("memory_bram -rules +/xilinx/drams.txt"); +				run("techmap -map +/xilinx/drams_map.v");  			}  		} -		if (check_label(active, run_from, run_to, "fine")) -		{ -			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 -				Pass::call(design, "pmux2shiftx"); -			} +		if (check_label("fine")) { +			run("opt -fast"); +			run("memory_map"); +			run("dffsr2dff"); +			run("dff2dffe"); -			Pass::call(design, "opt -fast -full"); -			Pass::call(design, "memory_map"); -			Pass::call(design, "dffsr2dff"); -			Pass::call(design, "dff2dffe"); +			// 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')"); -			if (vpr) { -				Pass::call(design, "techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); -			} else { -				Pass::call(design, "techmap -map +/xilinx/arith_map.v"); -			} +			run("opt -full"); -			Pass::call(design, "opt -full"); +			if (!vpr || help_mode) +				run("techmap -map +/xilinx/arith_map.v"); +			else +				run("techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); -			if (!nosrl) { +			if (!nosrl || help_mode) {  				// shregmap operates on bit-level flops, not word-level,  				//   so break those down here -				Pass::call(design, "simplemap t:$dff t:$dffe"); -				Pass::call(design, "show -format pdf -prefix show *depth=3*"); +				run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')");  				// shregmap with '-tech xilinx' infers variable length shift regs -				Pass::call(design, "shregmap -tech xilinx -minlen 3"); -				Pass::call(design, "opt -fast"); +				run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");  			} -			Pass::call(design, "techmap"); -			Pass::call(design, "opt -fast"); +			run("techmap"); +			run("opt -fast");  		} -		if (check_label(active, run_from, run_to, "map_cells")) -		{ -			Pass::call(design, "techmap -map +/xilinx/cells_map.v"); -			Pass::call(design, "clean"); +		if (check_label("map_cells")) { +			run("techmap -map +/techmap.v -map +/xilinx/cells_map.v"); +			run("clean");  		} -		if (check_label(active, run_from, run_to, "map_luts")) -		{ -			Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); -			Pass::call(design, "clean"); +		if (check_label("map_luts")) { +			if (help_mode) +				run("abc -luts 2:2,3,6:5,10,20 [-dff]"); +			else +				run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); +			run("clean");  			// This shregmap call infers fixed length shift registers after abc  			//   has performed any necessary retiming -			if (!nosrl) -				Pass::call(design, "shregmap -minlen 3 -init -params -enpol any_or_none"); -			Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); -			Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " +			if (!nosrl || help_mode) +				run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')"); +			run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); +			run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "  					"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); -			Pass::call(design, "clean"); +			run("clean");  		} -		if (check_label(active, run_from, run_to, "check")) -		{ -			Pass::call(design, "hierarchy -check"); -			Pass::call(design, "stat"); -			Pass::call(design, "check -noinit"); +		if (check_label("check")) { +			run("hierarchy -check"); +			run("stat"); +			run("check -noinit");  		} -		if (check_label(active, run_from, run_to, "edif")) -		{ -			if (!edif_file.empty()) -				Pass::call(design, stringf("write_edif -pvector bra %s", edif_file.c_str())); -		} -		if (check_label(active, run_from, run_to, "blif")) -		{ -			if (!blif_file.empty()) -				Pass::call(design, stringf("write_blif %s", edif_file.c_str())); +		if (check_label("edif")) { +			if (!edif_file.empty() || help_mode) +				run(stringf("write_edif -pvector bra %s", edif_file.c_str()));  		} -		log_pop(); +		if (check_label("blif")) { +			if (!blif_file.empty() || help_mode) +				run(stringf("write_blif %s", edif_file.c_str())); +		}  	}  } SynthXilinxPass; diff --git a/tests/memories/firrtl_938.v b/tests/memories/firrtl_938.v new file mode 100644 index 000000000..af5efcd25 --- /dev/null +++ b/tests/memories/firrtl_938.v @@ -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 diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl index 50d693513..ba61a4476 100644 --- a/tests/simple/xfirrtl +++ b/tests/simple/xfirrtl @@ -16,6 +16,7 @@ operators.v	$pow  partsel.v	drops modules  process.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)  sincos.v	$adff  specify.v	no code (empty module generates error  | 
