diff options
Diffstat (limited to 'backends')
| -rw-r--r-- | backends/smt2/smt2.cc | 237 | 
1 files changed, 157 insertions, 80 deletions
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 3d872c63a..af3d0ad32 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -32,7 +32,7 @@ struct Smt2Worker  	CellTypes ct;  	SigMap sigmap;  	RTLIL::Module *module; -	bool bvmode, verbose; +	bool bvmode, memmode, verbose;  	int idcounter;  	std::vector<std::string> decls, trans; @@ -41,10 +41,11 @@ struct Smt2Worker  	pool<Cell*> recursive_cells, registers;  	std::map<RTLIL::SigBit, std::pair<int, int>> fcache; +	std::map<Cell*, int> memarrays;  	std::map<int, int> bvsizes; -	Smt2Worker(RTLIL::Module *module, bool bvmode, bool verbose) : -			ct(module->design), sigmap(module), module(module), bvmode(bvmode), verbose(verbose), idcounter(0) +	Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool verbose) : +			ct(module->design), sigmap(module), module(module), bvmode(bvmode), memmode(memmode), verbose(verbose), idcounter(0)  	{  		decls.push_back(stringf("(declare-sort |%s_s| 0)\n", log_id(module))); @@ -316,6 +317,7 @@ struct Smt2Worker  		if (exported_cells.count(cell))  			return; +  		exported_cells.insert(cell);  		recursive_cells.insert(cell); @@ -345,89 +347,121 @@ struct Smt2Worker  		// FIXME: $lut -		if (!bvmode) -			log_error("Unsupported cell type %s for cell %s.%s. (Maybe this cell type would be supported in -bv mode?)\n", -					log_id(cell->type), log_id(module), log_id(cell)); - -		if (cell->type == "$dff") +		if (bvmode)  		{ -			registers.insert(cell); -			decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n", -					log_id(module), idcounter, log_id(module), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q")))); -			register_bv(cell->getPort("\\Q"), idcounter++); -			recursive_cells.erase(cell); -			return; +			if (cell->type == "$dff") +			{ +				registers.insert(cell); +				decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n", +						log_id(module), idcounter, log_id(module), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q")))); +				register_bv(cell->getPort("\\Q"), idcounter++); +				recursive_cells.erase(cell); +				return; +			} + +			if (cell->type == "$and") return export_bvop(cell, "(bvand A B)"); +			if (cell->type == "$or") return export_bvop(cell, "(bvor A B)"); +			if (cell->type == "$xor") return export_bvop(cell, "(bvxor A B)"); +			if (cell->type == "$xnor") return export_bvop(cell, "(bvxnor A B)"); + +			if (cell->type == "$shl") return export_bvop(cell, "(bvshl A B)", 's'); +			if (cell->type == "$shr") return export_bvop(cell, "(bvlshr A B)", 's'); +			if (cell->type == "$sshl") return export_bvop(cell, "(bvshl A B)", 's'); +			if (cell->type == "$sshr") return export_bvop(cell, "(bvLshr A B)", 's'); + +			// FIXME: $shift $shiftx + +			if (cell->type == "$lt") return export_bvop(cell, "(bvUlt A B)", 'b'); +			if (cell->type == "$le") return export_bvop(cell, "(bvUle A B)", 'b'); +			if (cell->type == "$ge") return export_bvop(cell, "(bvUge A B)", 'b'); +			if (cell->type == "$gt") return export_bvop(cell, "(bvUgt A B)", 'b'); + +			if (cell->type == "$ne") return export_bvop(cell, "(distinct A B)", 'b'); +			if (cell->type == "$nex") return export_bvop(cell, "(distinct A B)", 'b'); +			if (cell->type == "$eq") return export_bvop(cell, "(= A B)", 'b'); +			if (cell->type == "$eqx") return export_bvop(cell, "(= A B)", 'b'); + +			if (cell->type == "$not") return export_bvop(cell, "(bvnot A)"); +			if (cell->type == "$pos") return export_bvop(cell, "A"); +			if (cell->type == "$neg") return export_bvop(cell, "(bvneg A)"); + +			if (cell->type == "$add") return export_bvop(cell, "(bvadd A B)"); +			if (cell->type == "$sub") return export_bvop(cell, "(bvsub A B)"); +			if (cell->type == "$mul") return export_bvop(cell, "(bvmul A B)"); +			if (cell->type == "$div") return export_bvop(cell, "(bvUdiv A B)", 'd'); +			if (cell->type == "$mod") return export_bvop(cell, "(bvUrem A B)", 'd'); + +			if (cell->type == "$reduce_and") return export_reduce(cell, "(and A)", true); +			if (cell->type == "$reduce_or") return export_reduce(cell, "(or A)", false); +			if (cell->type == "$reduce_xor") return export_reduce(cell, "(xor A)", false); +			if (cell->type == "$reduce_xnor") return export_reduce(cell, "(not (xor A))", false); +			if (cell->type == "$reduce_bool") return export_reduce(cell, "(or A)", false); + +			if (cell->type == "$logic_not") return export_reduce(cell, "(not (or A))", false); +			if (cell->type == "$logic_and") return export_reduce(cell, "(and (or A) (or B))", false); +			if (cell->type == "$logic_or") return export_reduce(cell, "(or A B)", false); + +			if (cell->type == "$mux" || cell->type == "$pmux") +			{ +				int width = GetSize(cell->getPort("\\Y")); +				std::string processed_expr = get_bv(cell->getPort("\\A")); + +				RTLIL::SigSpec sig_b = cell->getPort("\\B"); +				RTLIL::SigSpec sig_s = cell->getPort("\\S"); +				get_bv(sig_b); +				get_bv(sig_s); + +				for (int i = 0; i < GetSize(sig_s); i++) +					processed_expr = stringf("(ite %s %s %s)", get_bool(sig_s[i]).c_str(), +							get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str()); + +				if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", +						log_id(cell)); +				RTLIL::SigSpec sig = sigmap(cell->getPort("\\Y")); +				decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", +						log_id(module), idcounter, log_id(module), width, processed_expr.c_str(), log_signal(sig))); +				register_bv(sig, idcounter++); +				recursive_cells.erase(cell); +				return; +			} + +			// FIXME: $slice $concat  		} -		if (cell->type == "$and") return export_bvop(cell, "(bvand A B)"); -		if (cell->type == "$or") return export_bvop(cell, "(bvor A B)"); -		if (cell->type == "$xor") return export_bvop(cell, "(bvxor A B)"); -		if (cell->type == "$xnor") return export_bvop(cell, "(bvxnor A B)"); - -		if (cell->type == "$shl") return export_bvop(cell, "(bvshl A B)", 's'); -		if (cell->type == "$shr") return export_bvop(cell, "(bvlshr A B)", 's'); -		if (cell->type == "$sshl") return export_bvop(cell, "(bvshl A B)", 's'); -		if (cell->type == "$sshr") return export_bvop(cell, "(bvLshr A B)", 's'); - -		// FIXME: $shift $shiftx - -		if (cell->type == "$lt") return export_bvop(cell, "(bvUlt A B)", 'b'); -		if (cell->type == "$le") return export_bvop(cell, "(bvUle A B)", 'b'); -		if (cell->type == "$ge") return export_bvop(cell, "(bvUge A B)", 'b'); -		if (cell->type == "$gt") return export_bvop(cell, "(bvUgt A B)", 'b'); - -		if (cell->type == "$ne") return export_bvop(cell, "(distinct A B)", 'b'); -		if (cell->type == "$nex") return export_bvop(cell, "(distinct A B)", 'b'); -		if (cell->type == "$eq") return export_bvop(cell, "(= A B)", 'b'); -		if (cell->type == "$eqx") return export_bvop(cell, "(= A B)", 'b'); - -		if (cell->type == "$not") return export_bvop(cell, "(bvnot A)"); -		if (cell->type == "$pos") return export_bvop(cell, "A"); -		if (cell->type == "$neg") return export_bvop(cell, "(bvneg A)"); - -		if (cell->type == "$add") return export_bvop(cell, "(bvadd A B)"); -		if (cell->type == "$sub") return export_bvop(cell, "(bvsub A B)"); -		if (cell->type == "$mul") return export_bvop(cell, "(bvmul A B)"); -		if (cell->type == "$div") return export_bvop(cell, "(bvUdiv A B)", 'd'); -		if (cell->type == "$mod") return export_bvop(cell, "(bvUrem A B)", 'd'); - -		if (cell->type == "$reduce_and") return export_reduce(cell, "(and A)", true); -		if (cell->type == "$reduce_or") return export_reduce(cell, "(or A)", false); -		if (cell->type == "$reduce_xor") return export_reduce(cell, "(xor A)", false); -		if (cell->type == "$reduce_xnor") return export_reduce(cell, "(not (xor A))", false); -		if (cell->type == "$reduce_bool") return export_reduce(cell, "(or A)", false); - -		if (cell->type == "$logic_not") return export_reduce(cell, "(not (or A))", false); -		if (cell->type == "$logic_and") return export_reduce(cell, "(and (or A) (or B))", false); -		if (cell->type == "$logic_or") return export_reduce(cell, "(or A B)", false); - -		if (cell->type == "$mux" || cell->type == "$pmux") +		if (memmode && cell->type == "$mem")  		{ -			int width = GetSize(cell->getPort("\\Y")); -			std::string processed_expr = get_bv(cell->getPort("\\A")); +			int arrayid = idcounter++; +			memarrays[cell] = arrayid; -			RTLIL::SigSpec sig_b = cell->getPort("\\B"); -			RTLIL::SigSpec sig_s = cell->getPort("\\S"); -			get_bv(sig_b); -			get_bv(sig_s); +			int abits = cell->getParam("\\ABITS").as_int(); +			int width = cell->getParam("\\WIDTH").as_int(); +			int rd_ports = cell->getParam("\\RD_PORTS").as_int(); -			for (int i = 0; i < GetSize(sig_s); i++) -				processed_expr = stringf("(ite %s %s %s)", get_bool(sig_s[i]).c_str(), -						get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str()); +			decls.push_back(stringf("(declare-fun |%s#%d#0| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n", +					log_id(module), arrayid, log_id(module), abits, width, log_id(cell))); -			if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", -					log_id(cell)); -			RTLIL::SigSpec sig = sigmap(cell->getPort("\\Y")); -			decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", -					log_id(module), idcounter, log_id(module), width, processed_expr.c_str(), log_signal(sig))); -			register_bv(sig, idcounter++); +			log_cell(cell); + +			for (int i = 0; i < rd_ports; i++) +			{ +				std::string addr = get_bv(cell->getPort("\\RD_ADDR").extract(abits*i, abits)); +				SigSpec data_sig = cell->getPort("\\RD_DATA").extract(width*i, width); + +				if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool()) +					log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! " +							"Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(data_sig), log_id(cell), log_id(module)); + +				decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) (select (|%s#%d#0| state) %s)) ; %s\n", +						log_id(module), idcounter, log_id(module), width, log_id(module), arrayid, addr.c_str(), log_signal(data_sig))); +				register_bv(data_sig, idcounter++); +			} + +			registers.insert(cell);  			recursive_cells.erase(cell);  			return;  		} -		// FIXME: $slice $concat - -		log_error("Unsupported cell type %s for cell %s.%s.\n", +		log_error("Unsupported cell type %s for cell %s.%s. (Maybe this cell type would be supported in -bv or -mem mode?)\n",  				log_id(cell->type), log_id(module), log_id(cell));  	} @@ -490,17 +524,49 @@ struct Smt2Worker  			if (verbose) log("=> export logic driving registers [iteration %d]\n", iter); -			for (auto cell : this_regs) { -				if (cell->type == "$_DFF_P_" || cell->type == "$_DFF_N_") { +			for (auto cell : this_regs) +			{ +				if (cell->type == "$_DFF_P_" || cell->type == "$_DFF_N_") +				{  					std::string expr_d = get_bool(cell->getPort("\\D"));  					std::string expr_q = get_bool(cell->getPort("\\Q"), "next_state");  					trans.push_back(stringf("  (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q"))));  				} -				if (cell->type == "$dff") { + +				if (cell->type == "$dff") +				{  					std::string expr_d = get_bv(cell->getPort("\\D"));  					std::string expr_q = get_bv(cell->getPort("\\Q"), "next_state");  					trans.push_back(stringf("  (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q"))));  				} + +				if (cell->type == "$mem") +				{ +					int arrayid = memarrays.at(cell); + +					int abits = cell->getParam("\\ABITS").as_int(); +					int width = cell->getParam("\\WIDTH").as_int(); +					int wr_ports = cell->getParam("\\WR_PORTS").as_int(); + +					for (int i = 0; i < wr_ports; i++) +					{ +						std::string addr = get_bv(cell->getPort("\\WR_ADDR").extract(abits*i, abits)); +						std::string data = get_bv(cell->getPort("\\WR_DATA").extract(width*i, width)); +						std::string mask = get_bv(cell->getPort("\\WR_EN").extract(width*i, width)); + +						data = stringf("(bvor (bvand %s %s) (bvand (select (|%s#%d#%d| state) %s) (bvnot %s)))", +								data.c_str(), mask.c_str(), log_id(module), arrayid, i, addr.c_str(), mask.c_str()); + +						decls.push_back(stringf("(define-fun |%s#%d#%d| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) " +								"(store (|%s#%d#%d| state) %s %s)) ; %s\n", +								log_id(module), arrayid, i+1, log_id(module), abits, width, +								log_id(module), arrayid, i, addr.c_str(), data.c_str(), log_id(cell))); +					} + +					std::string expr_d = stringf("(|%s#%d#%d| state)", log_id(module), arrayid, wr_ports); +					std::string expr_q = stringf("(|%s#%d#0| next_state)", log_id(module), arrayid); +					trans.push_back(stringf("  (= %s %s) ; %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell))); +				}  			}  		} @@ -591,6 +657,12 @@ struct Smt2Backend : public Backend {  		log("        option set multi-bit wires are represented using the BitVec sort and\n");  		log("        support for coarse grain cells (incl. arithmetic) is enabled.\n");  		log("\n"); +		log("    -mem\n"); +		log("        enable support for memories (via ArraysEx theory). this option\n"); +		log("        also implies -bv. only $mem cells without merged registers in\n"); +		log("        read ports are supported. call \"memory\" with -nordff to make sure\n"); +		log("        that no registers are merged into $mem read ports.\n"); +		log("\n");  		log("    -tpl <template_file>\n");  		log("        use the given template file. the line containing only the token '%%%%'\n");  		log("        is replaced with the regular output of this command.\n"); @@ -647,7 +719,7 @@ struct Smt2Backend : public Backend {  	virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)  	{  		std::ifstream template_f; -		bool bvmode = false, verbose = false; +		bool bvmode = false, memmode = false, verbose = false;  		log_header("Executing SMT2 backend.\n"); @@ -664,6 +736,11 @@ struct Smt2Backend : public Backend {  				bvmode = true;  				continue;  			} +			if (args[argidx] == "-mem") { +				bvmode = true; +				memmode = true; +				continue; +			}  			if (args[argidx] == "-verbose") {  				verbose = true;  				continue; @@ -693,7 +770,7 @@ struct Smt2Backend : public Backend {  			log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module)); -			Smt2Worker worker(module, bvmode, verbose); +			Smt2Worker worker(module, bvmode, memmode, verbose);  			worker.run();  			worker.write(*f);  		}  | 
