diff options
Diffstat (limited to 'passes')
| -rw-r--r-- | passes/memory/memory_bram.cc | 211 | ||||
| -rw-r--r-- | passes/memory/memory_collect.cc | 232 | ||||
| -rw-r--r-- | passes/memory/memory_dff.cc | 8 | ||||
| -rw-r--r-- | passes/memory/memory_map.cc | 219 | ||||
| -rw-r--r-- | passes/memory/memory_nordff.cc | 72 | ||||
| -rw-r--r-- | passes/memory/memory_unpack.cc | 116 | ||||
| -rw-r--r-- | passes/opt/opt_mem.cc | 87 | ||||
| -rw-r--r-- | passes/sat/clk2fflogic.cc | 113 | ||||
| -rw-r--r-- | passes/sat/sim.cc | 193 | 
9 files changed, 348 insertions, 903 deletions
| diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index 3cb0728b7..c6948fdba 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -18,6 +18,7 @@   */  #include "kernel/yosys.h" +#include "kernel/mem.h"  USING_YOSYS_NAMESPACE  PRIVATE_NAMESPACE_BEGIN @@ -400,9 +401,11 @@ struct rules_t  	}  }; -bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, const rules_t::match_t &match, dict<string, int> &match_properties, int mode) +bool replace_memory(Mem &orig_mem, const rules_t &rules, const rules_t::bram_t &bram, const rules_t::match_t &match, dict<string, int> &match_properties, int mode)  { -	Module *module = cell->module; +	// We will modify ports — make a copy of the structure. +	Mem mem(orig_mem); +	Module *module = mem.module;  	auto portinfos = bram.make_portinfos();  	int dup_count = 1; @@ -437,46 +440,17 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,  	log("    Mapping to bram type %s (variant %d):\n", log_id(bram.name), bram.variant);  	// bram.dump_config(); -	int mem_size = cell->getParam(ID::SIZE).as_int(); -	int mem_abits = cell->getParam(ID::ABITS).as_int(); -	int mem_width = cell->getParam(ID::WIDTH).as_int(); -	// int mem_offset = cell->getParam(ID::OFFSET).as_int(); - -	bool cell_init = !SigSpec(cell->getParam(ID::INIT)).is_fully_undef(); +	bool cell_init = !mem.inits.empty();  	vector<Const> initdata;  	if (cell_init) { -		Const initparam = cell->getParam(ID::INIT); -		initdata.reserve(mem_size); -		for (int i=0; i < mem_size; i++) -			initdata.push_back(initparam.extract(mem_width*i, mem_width, State::Sx)); +		Const initparam = mem.get_init_data(); +		initdata.reserve(mem.size); +		for (int i=0; i < mem.size; i++) +			initdata.push_back(initparam.extract(mem.width*i, mem.width, State::Sx));  	} -	int wr_ports = cell->getParam(ID::WR_PORTS).as_int(); -	auto wr_clken = SigSpec(cell->getParam(ID::WR_CLK_ENABLE)); -	auto wr_clkpol = SigSpec(cell->getParam(ID::WR_CLK_POLARITY)); -	wr_clken.extend_u0(wr_ports); -	wr_clkpol.extend_u0(wr_ports); - -	SigSpec wr_en = cell->getPort(ID::WR_EN); -	SigSpec wr_clk = cell->getPort(ID::WR_CLK); -	SigSpec wr_data = cell->getPort(ID::WR_DATA); -	SigSpec wr_addr = cell->getPort(ID::WR_ADDR); - -	int rd_ports = cell->getParam(ID::RD_PORTS).as_int(); -	auto rd_clken = SigSpec(cell->getParam(ID::RD_CLK_ENABLE)); -	auto rd_clkpol = SigSpec(cell->getParam(ID::RD_CLK_POLARITY)); -	auto rd_transp = SigSpec(cell->getParam(ID::RD_TRANSPARENT)); -	rd_clken.extend_u0(rd_ports); -	rd_clkpol.extend_u0(rd_ports); -	rd_transp.extend_u0(rd_ports); - -	SigSpec rd_en = cell->getPort(ID::RD_EN); -	SigSpec rd_clk = cell->getPort(ID::RD_CLK); -	SigSpec rd_data = cell->getPort(ID::RD_DATA); -	SigSpec rd_addr = cell->getPort(ID::RD_ADDR); - -	if (match.shuffle_enable && bram.dbits >= portinfos.at(match.shuffle_enable - 'A').enable*2 && portinfos.at(match.shuffle_enable - 'A').enable > 0 && wr_ports > 0) +	if (match.shuffle_enable && bram.dbits >= portinfos.at(match.shuffle_enable - 'A').enable*2 && portinfos.at(match.shuffle_enable - 'A').enable > 0 && !mem.wr_ports.empty())  	{  		int bucket_size = bram.dbits / portinfos.at(match.shuffle_enable - 'A').enable;  		log("      Shuffle bit order to accommodate enable buckets of size %d..\n", bucket_size); @@ -487,23 +461,23 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,  		std::vector<SigSpec> old_wr_data;  		std::vector<SigSpec> old_rd_data; -		for (int i = 0; i < wr_ports; i++) { -			old_wr_en.push_back(wr_en.extract(i*mem_width, mem_width)); -			old_wr_data.push_back(wr_data.extract(i*mem_width, mem_width)); +		for (auto &port : mem.wr_ports) { +			old_wr_en.push_back(port.en); +			old_wr_data.push_back(port.data);  		} -		for (int i = 0; i < rd_ports; i++) -			old_rd_data.push_back(rd_data.extract(i*mem_width, mem_width)); +		for (auto &port : mem.rd_ports) +			old_rd_data.push_back(port.data);  		// analyze enable structure  		std::vector<SigSpec> en_order;  		dict<SigSpec, vector<int>> bits_wr_en; -		for (int i = 0; i < mem_width; i++) { +		for (int i = 0; i < mem.width; i++) {  			SigSpec sig; -			for (int j = 0; j < wr_ports; j++) -				sig.append(old_wr_en[j][i]); +			for (auto &port : mem.wr_ports) +				sig.append(port.en[i]);  			if (bits_wr_en.count(sig) == 0)  				en_order.push_back(sig);  			bits_wr_en[sig].push_back(i); @@ -518,7 +492,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,  		std::vector<int> shuffle_map;  		if (cell_init) -			new_initdata.resize(mem_size); +			new_initdata.resize(mem.size);  		for (auto &it : en_order)  		{ @@ -528,29 +502,29 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,  			SigBit fillbit;  			for (int i = 0; i < GetSize(bits); i++) { -				for (int j = 0; j < wr_ports; j++) { +				for (int j = 0; j < GetSize(mem.wr_ports); j++) {  					new_wr_en[j].append(old_wr_en[j][bits[i]]);  					new_wr_data[j].append(old_wr_data[j][bits[i]]);  					fillbit = old_wr_en[j][bits[i]];  				} -				for (int j = 0; j < rd_ports; j++) +				for (int j = 0; j < GetSize(mem.rd_ports); j++)  					new_rd_data[j].append(old_rd_data[j][bits[i]]);  				if (cell_init) { -					for (int j = 0; j < mem_size; j++) +					for (int j = 0; j < mem.size; j++)  						new_initdata[j].push_back(initdata[j][bits[i]]);  				}  				shuffle_map.push_back(bits[i]);  			}  			for (int i = 0; i < fillbits; i++) { -				for (int j = 0; j < wr_ports; j++) { +				for (int j = 0; j < GetSize(mem.wr_ports); j++) {  					new_wr_en[j].append(fillbit);  					new_wr_data[j].append(State::S0);  				} -				for (int j = 0; j < rd_ports; j++) +				for (int j = 0; j < GetSize(mem.rd_ports); j++)  					new_rd_data[j].append(State::Sx);  				if (cell_init) { -					for (int j = 0; j < mem_size; j++) +					for (int j = 0; j < mem.size; j++)  						new_initdata[j].push_back(State::Sx);  				}  				shuffle_map.push_back(-1); @@ -564,40 +538,38 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,  		// update mem_*, wr_*, and rd_* variables -		mem_width = GetSize(new_wr_en.front()); -		wr_en = SigSpec(0, wr_ports * mem_width); -		wr_data = SigSpec(0, wr_ports * mem_width); -		rd_data = SigSpec(0, rd_ports * mem_width); +		mem.width = GetSize(new_wr_en.front()); -		for (int i = 0; i < wr_ports; i++) { -			wr_en.replace(i*mem_width, new_wr_en[i]); -			wr_data.replace(i*mem_width, new_wr_data[i]); +		for (int i = 0; i < GetSize(mem.wr_ports); i++) { +			auto &port = mem.wr_ports[i]; +			port.en = new_wr_en[i]; +			port.data = new_wr_data[i];  		} -		for (int i = 0; i < rd_ports; i++) -			rd_data.replace(i*mem_width, new_rd_data[i]); +		for (int i = 0; i < GetSize(mem.rd_ports); i++) { +			auto &port = mem.rd_ports[i]; +			port.data = new_rd_data[i]; +		}  		if (cell_init) { -			for (int i = 0; i < mem_size; i++) +			for (int i = 0; i < mem.size; i++)  				initdata[i] = Const(new_initdata[i]);  		}  	}  	// assign write ports  	pair<SigBit, bool> wr_clkdom; -	for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++) +	for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < GetSize(mem.wr_ports); cell_port_i++)  	{ -		bool clken = wr_clken[cell_port_i] == State::S1; -		bool clkpol = wr_clkpol[cell_port_i] == State::S1; -		SigBit clksig = wr_clk[cell_port_i]; +		auto &port = mem.wr_ports[cell_port_i]; -		pair<SigBit, bool> clkdom(clksig, clkpol); -		if (!clken) +		pair<SigBit, bool> clkdom(port.clk, port.clk_polarity); +		if (!port.clk_enable)  			clkdom = pair<SigBit, bool>(State::S1, false);  		wr_clkdom = clkdom;  		log("      Write port #%d is in clock domain %s%s.\n",  				cell_port_i, clkdom.second ? "" : "!", -				clken ? log_signal(clkdom.first) : "~async~"); +				port.clk_enable ? log_signal(clkdom.first) : "~async~");  		for (; bram_port_i < GetSize(portinfos); bram_port_i++)  		{ @@ -609,7 +581,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,  		skip_bram_wport:  				continue; -			if (clken) { +			if (port.clk_enable) {  				if (pi.clocks == 0) {  					log("        Bram port %c%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1);  					goto skip_bram_wport; @@ -618,7 +590,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,  					log("        Bram port %c%d is in a different clock domain.\n", pi.group + 'A', pi.index + 1);  					goto skip_bram_wport;  				} -				if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != clkpol) { +				if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != port.clk_polarity) {  					log("        Bram port %c%d has incompatible clock polarity.\n", pi.group + 'A', pi.index + 1);  					goto skip_bram_wport;  				} @@ -631,12 +603,12 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,  			SigSpec sig_en;  			SigBit last_en_bit = State::S1; -			for (int i = 0; i < mem_width; i++) { +			for (int i = 0; i < mem.width; i++) {  				if (pi.enable && i % (bram.dbits / pi.enable) == 0) { -					last_en_bit = wr_en[i + cell_port_i*mem_width]; +					last_en_bit = port.en[i];  					sig_en.append(last_en_bit);  				} -				if (last_en_bit != wr_en[i + cell_port_i*mem_width]) { +				if (last_en_bit != port.en[i]) {  					log("        Bram port %c%d has incompatible enable structure.\n", pi.group + 'A', pi.index + 1);  					goto skip_bram_wport;  				} @@ -645,7 +617,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,  			log("        Mapped to bram port %c%d.\n", pi.group + 'A', pi.index + 1);  			pi.mapped_port = cell_port_i; -			if (clken) { +			if (port.clk_enable) {  				clock_domains[pi.clocks] = clkdom;  				clock_polarities[pi.clkpol] = clkdom.second;  				pi.sig_clock = clkdom.first; @@ -653,8 +625,8 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,  			}  			pi.sig_en = sig_en; -			pi.sig_addr = wr_addr.extract(cell_port_i*mem_abits, mem_abits); -			pi.sig_data = wr_data.extract(cell_port_i*mem_width, mem_width); +			pi.sig_addr = port.addr; +			pi.sig_data = port.data;  			bram_port_i++;  			goto mapped_wr_port; @@ -710,23 +682,21 @@ grow_read_ports:;  	// assign read ports -	for (int cell_port_i = 0; cell_port_i < rd_ports; cell_port_i++) +	for (int cell_port_i = 0; cell_port_i < GetSize(mem.rd_ports); cell_port_i++)  	{ -		bool clken = rd_clken[cell_port_i] == State::S1; -		bool clkpol = rd_clkpol[cell_port_i] == State::S1; -		bool transp = rd_transp[cell_port_i] == State::S1; -		SigBit clksig = rd_clk[cell_port_i]; +		auto &port = mem.rd_ports[cell_port_i]; +		bool transp = port.transparent; -		if (wr_ports == 0) +		if (mem.wr_ports.empty())  			transp = false; -		pair<SigBit, bool> clkdom(clksig, clkpol); -		if (!clken) +		pair<SigBit, bool> clkdom(port.clk, port.clk_polarity); +		if (!port.clk_enable)  			clkdom = pair<SigBit, bool>(State::S1, false);  		log("      Read port #%d is in clock domain %s%s.\n",  				cell_port_i, clkdom.second ? "" : "!", -				clken ? log_signal(clkdom.first) : "~async~"); +				port.clk_enable ? log_signal(clkdom.first) : "~async~");  		for (int bram_port_i = 0; bram_port_i < GetSize(portinfos); bram_port_i++)  		{ @@ -736,7 +706,7 @@ grow_read_ports:;  		skip_bram_rport:  				continue; -			if (clken) { +			if (port.clk_enable) {  				if (pi.clocks == 0) {  					if (match.make_outreg) {  						pi.make_outreg = true; @@ -749,20 +719,20 @@ grow_read_ports:;  					log("        Bram port %c%d.%d is in a different clock domain.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);  					goto skip_bram_rport;  				} -				if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != clkpol) { +				if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != port.clk_polarity) {  					log("        Bram port %c%d.%d has incompatible clock polarity.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);  					goto skip_bram_rport;  				} -				if (rd_en[cell_port_i] != State::S1 && pi.enable == 0) { +				if (port.en != State::S1 && pi.enable == 0) {  					log("        Bram port %c%d.%d has no read enable input.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);  					goto skip_bram_rport;  				}  			skip_bram_rport_clkcheck:  				if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) { -					if (match.make_transp && wr_ports <= 1) { +					if (match.make_transp && GetSize(mem.wr_ports) <= 1) {  						pi.make_transp = true;  						if (pi.clocks != 0) { -							if (wr_ports == 1 && wr_clkdom != clkdom) { +							if (GetSize(mem.wr_ports) == 1 && wr_clkdom != clkdom) {  								log("        Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);  								goto skip_bram_rport;  							} @@ -783,18 +753,18 @@ grow_read_ports:;  			log("        Mapped to bram port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);  			pi.mapped_port = cell_port_i; -			if (clken) { +			if (port.clk_enable) {  				clock_domains[pi.clocks] = clkdom;  				clock_polarities[pi.clkpol] = clkdom.second;  				if (!pi.make_transp)  					read_transp[pi.transp] = transp;  				pi.sig_clock = clkdom.first; -				pi.sig_en = rd_en[cell_port_i]; +				pi.sig_en = port.en;  				pi.effective_clkpol = clkdom.second;  			} -			pi.sig_addr = rd_addr.extract(cell_port_i*mem_abits, mem_abits); -			pi.sig_data = rd_data.extract(cell_port_i*mem_width, mem_width); +			pi.sig_addr = port.addr; +			pi.sig_data = port.data;  			if (grow_read_ports_cursor < cell_port_i) {  				grow_read_ports_cursor = cell_port_i; @@ -820,11 +790,11 @@ grow_read_ports:;  		match_properties["dups"] = dup_count;  		match_properties["waste"] = match_properties["dups"] * match_properties["bwaste"]; -		int cells = ((mem_width + bram.dbits - 1) / bram.dbits) * ((mem_size + (1 << bram.abits) - 1) / (1 << bram.abits)); +		int cells = ((mem.width + bram.dbits - 1) / bram.dbits) * ((mem.size + (1 << bram.abits) - 1) / (1 << bram.abits));  		match_properties["efficiency"] = (100 * match_properties["bits"]) / (dup_count * cells * bram.dbits * (1 << bram.abits)); -		match_properties["dcells"] = ((mem_width + bram.dbits - 1) / bram.dbits); -		match_properties["acells"] = ((mem_size + (1 << bram.abits) - 1) / (1 << bram.abits)); +		match_properties["dcells"] = ((mem.width + bram.dbits - 1) / bram.dbits); +		match_properties["acells"] = ((mem.size + (1 << bram.abits) - 1) / (1 << bram.abits));  		match_properties["cells"] = match_properties["dcells"] *  match_properties["acells"] * match_properties["dups"];  		log("      Updated properties: dups=%d waste=%d efficiency=%d\n", @@ -857,8 +827,8 @@ grow_read_ports:;  				bool exists = std::get<0>(term);  				IdString key = std::get<1>(term);  				const Const &value = std::get<2>(term); -				auto it = cell->attributes.find(key); -				if (it == cell->attributes.end()) { +				auto it = mem.attributes.find(key); +				if (it == mem.attributes.end()) {  					if (exists)  						continue;  					found = true; @@ -902,7 +872,7 @@ grow_read_ports:;  	dict<SigSpec, pair<SigSpec, SigSpec>> dout_cache; -	for (int grid_d = 0; grid_d*bram.dbits < mem_width; grid_d++) +	for (int grid_d = 0; grid_d*bram.dbits < mem.width; grid_d++)  	{  		SigSpec mktr_wraddr, mktr_wrdata, mktr_wrdata_q;  		vector<SigSpec> mktr_wren; @@ -912,14 +882,14 @@ grow_read_ports:;  			mktr_wrdata = module->addWire(NEW_ID, bram.dbits);  			mktr_wrdata_q = module->addWire(NEW_ID, bram.dbits);  			module->addDff(NEW_ID, make_transp_clk.first, mktr_wrdata, mktr_wrdata_q, make_transp_clk.second); -			for (int grid_a = 0; grid_a*(1 << bram.abits) < mem_size; grid_a++) +			for (int grid_a = 0; grid_a*(1 << bram.abits) < mem.size; grid_a++)  				mktr_wren.push_back(module->addWire(NEW_ID, make_transp_enbits));  		} -		for (int grid_a = 0; grid_a*(1 << bram.abits) < mem_size; grid_a++) +		for (int grid_a = 0; grid_a*(1 << bram.abits) < mem.size; grid_a++)  		for (int dupidx = 0; dupidx < dup_count; dupidx++)  		{ -			Cell *c = module->addCell(module->uniquify(stringf("%s.%d.%d.%d", cell->name.c_str(), grid_d, grid_a, dupidx)), bram.name); +			Cell *c = module->addCell(module->uniquify(stringf("%s.%d.%d.%d", mem.memid.c_str(), grid_d, grid_a, dupidx)), bram.name);  			log("      Creating %s cell at grid position <%d %d %d>: %s\n", log_id(bram.name), grid_d, grid_a, dupidx, log_id(c));  			for (auto &vp : variant_params) @@ -1063,22 +1033,22 @@ grow_read_ports:;  		}  	} -	module->remove(cell); +	mem.remove();  	return true;  } -void handle_cell(Cell *cell, const rules_t &rules) +void handle_memory(Mem &mem, const rules_t &rules)  { -	log("Processing %s.%s:\n", log_id(cell->module), log_id(cell)); +	log("Processing %s.%s:\n", log_id(mem.module), log_id(mem.memid)); -	bool cell_init = !SigSpec(cell->getParam(ID::INIT)).is_fully_undef(); +	bool cell_init = !mem.inits.empty();  	dict<string, int> match_properties; -	match_properties["words"]  = cell->getParam(ID::SIZE).as_int(); -	match_properties["abits"]  = cell->getParam(ID::ABITS).as_int(); -	match_properties["dbits"]  = cell->getParam(ID::WIDTH).as_int(); -	match_properties["wports"] = cell->getParam(ID::WR_PORTS).as_int(); -	match_properties["rports"] = cell->getParam(ID::RD_PORTS).as_int(); +	match_properties["words"]  = mem.size; +	match_properties["abits"]  = ceil_log2(mem.size); +	match_properties["dbits"]  = mem.width; +	match_properties["wports"] = GetSize(mem.wr_ports); +	match_properties["rports"] = GetSize(mem.rd_ports);  	match_properties["bits"]   = match_properties["words"] * match_properties["dbits"];  	match_properties["ports"]  = match_properties["wports"] + match_properties["rports"]; @@ -1181,8 +1151,8 @@ void handle_cell(Cell *cell, const rules_t &rules)  					bool exists = std::get<0>(term);  					IdString key = std::get<1>(term);  					const Const &value = std::get<2>(term); -					auto it = cell->attributes.find(key); -					if (it == cell->attributes.end()) { +					auto it = mem.attributes.find(key); +					if (it == mem.attributes.end()) {  						if (exists)  							continue;  						found = true; @@ -1219,7 +1189,7 @@ void handle_cell(Cell *cell, const rules_t &rules)  				if (or_next_if_better && i+1 == GetSize(rules.matches) && vi+1 == GetSize(rules.brams.at(match.name)))  					log_error("Found 'or_next_if_better' in last match rule.\n"); -				if (!replace_cell(cell, rules, bram, match, match_properties, 1)) { +				if (!replace_memory(mem, rules, bram, match, match_properties, 1)) {  					log("    Mapping to bram type %s failed.\n", log_id(match.name));  					failed_brams.insert(pair<IdString, int>(bram.name, bram.variant));  					goto next_match_rule; @@ -1246,12 +1216,12 @@ void handle_cell(Cell *cell, const rules_t &rules)  				best_rule_cache.clear();  				auto &best_bram = rules.brams.at(rules.matches.at(best_rule.first).name).at(best_rule.second); -				if (!replace_cell(cell, rules, best_bram, rules.matches.at(best_rule.first), match_properties, 2)) +				if (!replace_memory(mem, rules, best_bram, rules.matches.at(best_rule.first), match_properties, 2))  					log_error("Mapping to bram type %s (variant %d) after pre-selection failed.\n", log_id(best_bram.name), best_bram.variant);  				return;  			} -			if (!replace_cell(cell, rules, bram, match, match_properties, 0)) { +			if (!replace_memory(mem, rules, bram, match, match_properties, 0)) {  				log("    Mapping to bram type %s failed.\n", log_id(match.name));  				failed_brams.insert(pair<IdString, int>(bram.name, bram.variant));  				goto next_match_rule; @@ -1384,9 +1354,8 @@ struct MemoryBramPass : public Pass {  		extra_args(args, argidx, design);  		for (auto mod : design->selected_modules()) -		for (auto cell : mod->selected_cells()) -			if (cell->type == ID($mem)) -				handle_cell(cell, rules); +		for (auto &mem : Mem::get_selected_memories(mod)) +			handle_memory(mem, rules);  	}  } MemoryBramPass; diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc index 7e82f47dc..ede6ca6a1 100644 --- a/passes/memory/memory_collect.cc +++ b/passes/memory/memory_collect.cc @@ -18,231 +18,11 @@   */  #include "kernel/yosys.h" -#include "kernel/sigtools.h" +#include "kernel/mem.h"  USING_YOSYS_NAMESPACE  PRIVATE_NAMESPACE_BEGIN -bool memcells_cmp(Cell *a, Cell *b) -{ -	if (a->type == ID($memrd) && b->type == ID($memrd)) -		return a->name < b->name; -	if (a->type == ID($memrd) || b->type == ID($memrd)) -		return (a->type == ID($memrd)) < (b->type == ID($memrd)); -	return a->parameters.at(ID::PRIORITY).as_int() < b->parameters.at(ID::PRIORITY).as_int(); -} - -Cell *handle_memory(Module *module, RTLIL::Memory *memory) -{ -	log("Collecting $memrd, $memwr and $meminit for memory `%s' in module `%s':\n", -			memory->name.c_str(), module->name.c_str()); - -	Const init_data(State::Sx, memory->size * memory->width); -	SigMap sigmap(module); - -	int wr_ports = 0; -	SigSpec sig_wr_clk; -	SigSpec sig_wr_clk_enable; -	SigSpec sig_wr_clk_polarity; -	SigSpec sig_wr_addr; -	SigSpec sig_wr_data; -	SigSpec sig_wr_en; - -	int rd_ports = 0; -	SigSpec sig_rd_clk; -	SigSpec sig_rd_clk_enable; -	SigSpec sig_rd_clk_polarity; -	SigSpec sig_rd_transparent; -	SigSpec sig_rd_addr; -	SigSpec sig_rd_data; -	SigSpec sig_rd_en; - -	int addr_bits = 0; -	std::vector<Cell*> memcells; - -	for (auto cell : module->cells()) -		if (cell->type.in(ID($memrd), ID($memwr), ID($meminit)) && memory->name == cell->parameters[ID::MEMID].decode_string()) { -			SigSpec addr = sigmap(cell->getPort(ID::ADDR)); -			for (int i = 0; i < GetSize(addr); i++) -				if (addr[i] != State::S0) -					addr_bits = std::max(addr_bits, i+1); -			memcells.push_back(cell); -		} - -	if (memory->start_offset == 0 && addr_bits < 30 && (1 << addr_bits) < memory->size) -		memory->size = 1 << addr_bits; - -	if (memory->start_offset >= 0) -		addr_bits = std::min(addr_bits, ceil_log2(memory->size + memory->start_offset)); - -	addr_bits = std::max(addr_bits, 1); - -	if (memcells.empty()) { -		log("  no cells found. removing memory.\n"); -		return nullptr; -	} - -	std::sort(memcells.begin(), memcells.end(), memcells_cmp); - -	for (auto cell : memcells) -	{ -		log("  %s (%s)\n", log_id(cell), log_id(cell->type)); - -		if (cell->type == ID($meminit)) -		{ -			SigSpec addr = sigmap(cell->getPort(ID::ADDR)); -			SigSpec data = sigmap(cell->getPort(ID::DATA)); - -			if (!addr.is_fully_const()) -				log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr), log_id(cell)); -			if (!data.is_fully_const()) -				log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data), log_id(cell)); - -			int offset = (addr.as_int() - memory->start_offset) * memory->width; - -			if (offset < 0 || offset + GetSize(data) > GetSize(init_data)) -				log_warning("Address %s in memory initialization %s is out-of-bounds.\n", log_signal(addr), log_id(cell)); - -			for (int i = 0; i < GetSize(data); i++) -				if (0 <= i+offset && i+offset < GetSize(init_data)) -					init_data.bits[i+offset] = data[i].data; - -			continue; -		} - -		if (cell->type == ID($memwr)) -		{ -			SigSpec clk = sigmap(cell->getPort(ID::CLK)); -			SigSpec clk_enable = SigSpec(cell->parameters[ID::CLK_ENABLE]); -			SigSpec clk_polarity = SigSpec(cell->parameters[ID::CLK_POLARITY]); -			SigSpec addr = sigmap(cell->getPort(ID::ADDR)); -			SigSpec data = sigmap(cell->getPort(ID::DATA)); -			SigSpec en = sigmap(cell->getPort(ID::EN)); - -			if (!en.is_fully_zero()) -			{ -				clk.extend_u0(1, false); -				clk_enable.extend_u0(1, false); -				clk_polarity.extend_u0(1, false); -				addr.extend_u0(addr_bits, false); -				data.extend_u0(memory->width, false); -				en.extend_u0(memory->width, false); - -				sig_wr_clk.append(clk); -				sig_wr_clk_enable.append(clk_enable); -				sig_wr_clk_polarity.append(clk_polarity); -				sig_wr_addr.append(addr); -				sig_wr_data.append(data); -				sig_wr_en.append(en); - -				wr_ports++; -			} -			continue; -		} - -		if (cell->type == ID($memrd)) -		{ -			SigSpec clk = sigmap(cell->getPort(ID::CLK)); -			SigSpec clk_enable = SigSpec(cell->parameters[ID::CLK_ENABLE]); -			SigSpec clk_polarity = SigSpec(cell->parameters[ID::CLK_POLARITY]); -			SigSpec transparent = SigSpec(cell->parameters[ID::TRANSPARENT]); -			SigSpec addr = sigmap(cell->getPort(ID::ADDR)); -			SigSpec data = sigmap(cell->getPort(ID::DATA)); -			SigSpec en = sigmap(cell->getPort(ID::EN)); - -			if (!en.is_fully_zero()) -			{ -				clk.extend_u0(1, false); -				clk_enable.extend_u0(1, false); -				clk_polarity.extend_u0(1, false); -				transparent.extend_u0(1, false); -				addr.extend_u0(addr_bits, false); -				data.extend_u0(memory->width, false); - -				sig_rd_clk.append(clk); -				sig_rd_clk_enable.append(clk_enable); -				sig_rd_clk_polarity.append(clk_polarity); -				sig_rd_transparent.append(transparent); -				sig_rd_addr.append(addr); -				sig_rd_data.append(data); -				sig_rd_en.append(en); - -				rd_ports++; -			} -			continue; -		} -	} - -	std::stringstream sstr; -	sstr << "$mem$" << memory->name.str() << "$" << (autoidx++); - -	Cell *mem = module->addCell(sstr.str(), ID($mem)); -	mem->parameters[ID::MEMID] = Const(memory->name.str()); -	mem->parameters[ID::WIDTH] = Const(memory->width); -	mem->parameters[ID::OFFSET] = Const(memory->start_offset); -	mem->parameters[ID::SIZE] = Const(memory->size); -	mem->parameters[ID::ABITS] = Const(addr_bits); -	mem->parameters[ID::INIT] = init_data; - -	log_assert(sig_wr_clk.size() == wr_ports); -	log_assert(sig_wr_clk_enable.size() == wr_ports && sig_wr_clk_enable.is_fully_const()); -	log_assert(sig_wr_clk_polarity.size() == wr_ports && sig_wr_clk_polarity.is_fully_const()); -	log_assert(sig_wr_addr.size() == wr_ports * addr_bits); -	log_assert(sig_wr_data.size() == wr_ports * memory->width); -	log_assert(sig_wr_en.size() == wr_ports * memory->width); - -	mem->parameters[ID::WR_PORTS] = Const(wr_ports); -	mem->parameters[ID::WR_CLK_ENABLE] = wr_ports ? sig_wr_clk_enable.as_const() : State::S0; -	mem->parameters[ID::WR_CLK_POLARITY] = wr_ports ? sig_wr_clk_polarity.as_const() : State::S0; - -	mem->setPort(ID::WR_CLK, sig_wr_clk); -	mem->setPort(ID::WR_ADDR, sig_wr_addr); -	mem->setPort(ID::WR_DATA, sig_wr_data); -	mem->setPort(ID::WR_EN, sig_wr_en); - -	log_assert(sig_rd_clk.size() == rd_ports); -	log_assert(sig_rd_clk_enable.size() == rd_ports && sig_rd_clk_enable.is_fully_const()); -	log_assert(sig_rd_clk_polarity.size() == rd_ports && sig_rd_clk_polarity.is_fully_const()); -	log_assert(sig_rd_addr.size() == rd_ports * addr_bits); -	log_assert(sig_rd_data.size() == rd_ports * memory->width); - -	mem->parameters[ID::RD_PORTS] = Const(rd_ports); -	mem->parameters[ID::RD_CLK_ENABLE] = rd_ports ? sig_rd_clk_enable.as_const() : State::S0; -	mem->parameters[ID::RD_CLK_POLARITY] = rd_ports ? sig_rd_clk_polarity.as_const() : State::S0; -	mem->parameters[ID::RD_TRANSPARENT] = rd_ports ? sig_rd_transparent.as_const() : State::S0; - -	mem->setPort(ID::RD_CLK, sig_rd_clk); -	mem->setPort(ID::RD_ADDR, sig_rd_addr); -	mem->setPort(ID::RD_DATA, sig_rd_data); -	mem->setPort(ID::RD_EN, sig_rd_en); - -	// Copy attributes from RTLIL memory to $mem -	for (auto attr : memory->attributes) -		mem->attributes[attr.first] = attr.second; - -	for (auto c : memcells) -		module->remove(c); - -	return mem; -} - -static void handle_module(Design *design, Module *module) -{ -	std::vector<pair<Cell*, IdString>> finqueue; - -	for (auto &mem_it : module->memories) -		if (design->selected(module, mem_it.second)) { -			Cell *c = handle_memory(module, mem_it.second); -			finqueue.push_back(pair<Cell*, IdString>(c, mem_it.first)); -		} -	for (auto &it : finqueue) { -		delete module->memories.at(it.second); -		module->memories.erase(it.second); -		if (it.first) -			module->rename(it.first, it.second); -	} -} -  struct MemoryCollectPass : public Pass {  	MemoryCollectPass() : Pass("memory_collect", "creating multi-port memory cells") { }  	void help() override @@ -258,8 +38,14 @@ struct MemoryCollectPass : public Pass {  	void execute(std::vector<std::string> args, RTLIL::Design *design) override {  		log_header(design, "Executing MEMORY_COLLECT pass (generating $mem cells).\n");  		extra_args(args, 1, design); -		for (auto module : design->selected_modules()) -			handle_module(design, module); +		for (auto module : design->selected_modules()) { +			for (auto &mem : Mem::get_selected_memories(module)) { +				if (!mem.packed) { +					mem.packed = true; +					mem.emit(); +				} +			} +		}  	}  } MemoryCollectPass; diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index 68023fd11..4adcb462e 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -46,8 +46,15 @@ struct MemoryDffWorker  	{  		sigmap.apply(sig); +		dict<SigBit, SigBit> cache; +  		for (auto &bit : sig)  		{ +			if (cache.count(bit)) { +				bit = cache[bit]; +				continue; +			} +  			if (bit.wire == NULL)  				continue; @@ -103,6 +110,7 @@ struct MemoryDffWorker  						d = module->Mux(NEW_ID, rbit, d, cell->getPort(ID::SRST));  				} +				cache[bit] = d;  				bit = d;  				clk = this_clk;  				clk_polarity = this_clk_polarity; diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 80dd3957d..032b8fbbd 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -19,6 +19,7 @@  #include "kernel/register.h"  #include "kernel/log.h" +#include "kernel/mem.h"  #include <sstream>  #include <set>  #include <stdlib.h> @@ -97,35 +98,26 @@ struct MemoryMapWorker  		return bit.wire;  	} -	void handle_cell(RTLIL::Cell *cell) +	void handle_memory(Mem &mem)  	{  		std::set<int> static_ports;  		std::map<int, RTLIL::SigSpec> static_cells_map; -		int wr_ports = cell->parameters[ID::WR_PORTS].as_int(); -		int rd_ports = cell->parameters[ID::RD_PORTS].as_int(); - -		int mem_size = cell->parameters[ID::SIZE].as_int(); -		int mem_width = cell->parameters[ID::WIDTH].as_int(); -		int mem_offset = cell->parameters[ID::OFFSET].as_int(); -		int mem_abits = cell->parameters[ID::ABITS].as_int(); - -		SigSpec init_data = cell->getParam(ID::INIT); -		init_data.extend_u0(mem_size*mem_width, true); +		SigSpec init_data = mem.get_init_data();  		// delete unused memory cell -		if (wr_ports == 0 && rd_ports == 0) { -			module->remove(cell); +		if (mem.rd_ports.empty()) { +			mem.remove();  			return;  		} -		// check if attributes allow us to infer FFRAM for this cell +		// check if attributes allow us to infer FFRAM for this memory  		for (const auto &attr : attributes) { -			if (cell->attributes.count(attr.first)) { -				const auto &cell_attr = cell->attributes[attr.first]; +			if (mem.attributes.count(attr.first)) { +				const auto &cell_attr = mem.attributes[attr.first];  				if (attr.second.empty()) { -					log("Not mapping memory cell %s in module %s (attribute %s is set).\n", -							cell->name.c_str(), module->name.c_str(), attr.first.c_str()); +					log("Not mapping memory %s in module %s (attribute %s is set).\n", +							mem.memid.c_str(), module->name.c_str(), attr.first.c_str());  					return;  				} @@ -138,11 +130,11 @@ struct MemoryMapWorker  				}  				if (!found) {  					if (cell_attr.flags & RTLIL::CONST_FLAG_STRING) { -						log("Not mapping memory cell %s in module %s (attribute %s is set to \"%s\").\n", -								cell->name.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.decode_string().c_str()); +						log("Not mapping memory %s in module %s (attribute %s is set to \"%s\").\n", +								mem.memid.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.decode_string().c_str());  					} else { -						log("Not mapping memory cell %s in module %s (attribute %s is set to %d).\n", -								cell->name.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.as_int()); +						log("Not mapping memory %s in module %s (attribute %s is set to %d).\n", +								mem.memid.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.as_int());  					}  					return;  				} @@ -150,82 +142,75 @@ struct MemoryMapWorker  		}  		// all write ports must share the same clock -		RTLIL::SigSpec clocks = cell->getPort(ID::WR_CLK); -		RTLIL::Const clocks_pol = cell->parameters[ID::WR_CLK_POLARITY]; -		RTLIL::Const clocks_en = cell->parameters[ID::WR_CLK_ENABLE]; -		clocks_pol.bits.resize(wr_ports); -		clocks_en.bits.resize(wr_ports);  		RTLIL::SigSpec refclock; -		RTLIL::State refclock_pol = RTLIL::State::Sx; -		for (int i = 0; i < clocks.size(); i++) { -			RTLIL::SigSpec wr_en = cell->getPort(ID::WR_EN).extract(i * mem_width, mem_width); -			if (wr_en.is_fully_const() && !wr_en.as_bool()) { +		bool refclock_pol = false; +		for (int i = 0; i < GetSize(mem.wr_ports); i++) { +			auto &port = mem.wr_ports[i]; +			if (port.en.is_fully_const() && !port.en.as_bool()) {  				static_ports.insert(i);  				continue;  			} -			if (clocks_en.bits[i] != RTLIL::State::S1) { -				RTLIL::SigSpec wr_addr = cell->getPort(ID::WR_ADDR).extract(i*mem_abits, mem_abits); -				RTLIL::SigSpec wr_data = cell->getPort(ID::WR_DATA).extract(i*mem_width, mem_width); -				if (wr_addr.is_fully_const()) { -					// FIXME: Actually we should check for wr_en.is_fully_const() also and -					// create a $adff cell with this ports wr_en input as reset pin when wr_en +			if (!port.clk_enable) { +				if (port.addr.is_fully_const()) { +					// FIXME: Actually we should check for port.en.is_fully_const() also and +					// create a $adff cell with this ports port.en input as reset pin when port.en  					// is not a simple static 1. -					static_cells_map[wr_addr.as_int() - mem_offset] = wr_data; +					static_cells_map[port.addr.as_int() - mem.start_offset] = port.data;  					static_ports.insert(i);  					continue;  				} -				log("Not mapping memory cell %s in module %s (write port %d has no clock).\n", -						cell->name.c_str(), module->name.c_str(), i); +				log("Not mapping memory %s in module %s (write port %d has no clock).\n", +						mem.memid.c_str(), module->name.c_str(), i);  				return;  			}  			if (refclock.size() == 0) { -				refclock = clocks.extract(i, 1); -				refclock_pol = clocks_pol.bits[i]; +				refclock = port.clk; +				refclock_pol = port.clk_polarity;  			} -			if (clocks.extract(i, 1) != refclock || clocks_pol.bits[i] != refclock_pol) { -				log("Not mapping memory cell %s in module %s (write clock %d is incompatible with other clocks).\n", -						cell->name.c_str(), module->name.c_str(), i); +			if (port.clk != refclock || port.clk_polarity != refclock_pol) { +				log("Not mapping memory %s in module %s (write clock %d is incompatible with other clocks).\n", +						mem.memid.c_str(), module->name.c_str(), i);  				return;  			}  		} -		log("Mapping memory cell %s in module %s:\n", cell->name.c_str(), module->name.c_str()); +		log("Mapping memory %s in module %s:\n", mem.memid.c_str(), module->name.c_str());  		std::vector<RTLIL::SigSpec> data_reg_in;  		std::vector<RTLIL::SigSpec> data_reg_out;  		int count_static = 0; -		for (int i = 0; i < mem_size; i++) +		for (int i = 0; i < mem.size; i++)  		{  			if (static_cells_map.count(i) > 0)  			{ -				data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem_width)); +				data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem.width));  				data_reg_out.push_back(static_cells_map[i]);  				count_static++;  			}  			else  			{ -				RTLIL::Cell *c = module->addCell(genid(cell->name, "", i), ID($dff)); -				c->parameters[ID::WIDTH] = cell->parameters[ID::WIDTH]; -				if (clocks_pol.bits.size() > 0) { -					c->parameters[ID::CLK_POLARITY] = RTLIL::Const(clocks_pol.bits[0]); -					c->setPort(ID::CLK, clocks.extract(0, 1)); +				RTLIL::Cell *c = module->addCell(genid(mem.memid, "", i), ID($dff)); +				c->parameters[ID::WIDTH] = mem.width; +				if (GetSize(refclock) != 0) { +					c->parameters[ID::CLK_POLARITY] = RTLIL::Const(refclock_pol); +					c->setPort(ID::CLK, refclock);  				} else {  					c->parameters[ID::CLK_POLARITY] = RTLIL::Const(RTLIL::State::S1);  					c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0));  				} -				RTLIL::Wire *w_in = module->addWire(genid(cell->name, "", i, "$d"), mem_width); +				RTLIL::Wire *w_in = module->addWire(genid(mem.memid, "", i, "$d"), mem.width);  				data_reg_in.push_back(RTLIL::SigSpec(w_in));  				c->setPort(ID::D, data_reg_in.back()); -				std::string w_out_name = stringf("%s[%d]", cell->parameters[ID::MEMID].decode_string().c_str(), i); +				std::string w_out_name = stringf("%s[%d]", mem.memid.c_str(), i);  				if (module->wires_.count(w_out_name) > 0) -					w_out_name = genid(cell->name, "", i, "$q"); +					w_out_name = genid(mem.memid, "", i, "$q"); -				RTLIL::Wire *w_out = module->addWire(w_out_name, mem_width); -				SigSpec w_init = init_data.extract(i*mem_width, mem_width); +				RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width); +				SigSpec w_init = init_data.extract(i*mem.width, mem.width);  				if (!w_init.is_fully_undef())  					w_out->attributes[ID::init] = w_init.as_const(); @@ -235,76 +220,39 @@ struct MemoryMapWorker  			}  		} -		log("  created %d $dff cells and %d static cells of width %d.\n", mem_size-count_static, count_static, mem_width); +		log("  created %d $dff cells and %d static cells of width %d.\n", mem.size-count_static, count_static, mem.width);  		int count_dff = 0, count_mux = 0, count_wrmux = 0; -		for (int i = 0; i < cell->parameters[ID::RD_PORTS].as_int(); i++) +		int abits = ceil_log2(mem.size); +		for (int i = 0; i < GetSize(mem.rd_ports); i++)  		{ -			RTLIL::SigSpec rd_addr = cell->getPort(ID::RD_ADDR).extract(i*mem_abits, mem_abits); +			auto &port = mem.rd_ports[i]; +			if (mem.extract_rdff(i)) +				count_dff++; +			RTLIL::SigSpec rd_addr = port.addr; +			rd_addr.extend_u0(abits, false); -			if (mem_offset) -				rd_addr = module->Sub(NEW_ID, rd_addr, SigSpec(mem_offset, GetSize(rd_addr))); +			if (mem.start_offset) +				rd_addr = module->Sub(NEW_ID, rd_addr, SigSpec(mem.start_offset, abits));  			std::vector<RTLIL::SigSpec> rd_signals; -			rd_signals.push_back(cell->getPort(ID::RD_DATA).extract(i*mem_width, mem_width)); - -			if (cell->parameters[ID::RD_CLK_ENABLE].bits[i] == RTLIL::State::S1) -			{ -				RTLIL::Cell *dff_cell = nullptr; - -				if (cell->parameters[ID::RD_TRANSPARENT].bits[i] == RTLIL::State::S1) -				{ -					dff_cell = module->addCell(genid(cell->name, "$rdreg", i), ID($dff)); -					dff_cell->parameters[ID::WIDTH] = RTLIL::Const(mem_abits); -					dff_cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(cell->parameters[ID::RD_CLK_POLARITY].bits[i]); -					dff_cell->setPort(ID::CLK, cell->getPort(ID::RD_CLK).extract(i, 1)); -					dff_cell->setPort(ID::D, rd_addr); -					count_dff++; - -					RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$q"), mem_abits); - -					dff_cell->setPort(ID::Q, RTLIL::SigSpec(w)); -					rd_addr = RTLIL::SigSpec(w); -				} -				else -				{ -					dff_cell = module->addCell(genid(cell->name, "$rdreg", i), ID($dff)); -					dff_cell->parameters[ID::WIDTH] = cell->parameters[ID::WIDTH]; -					dff_cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(cell->parameters[ID::RD_CLK_POLARITY].bits[i]); -					dff_cell->setPort(ID::CLK, cell->getPort(ID::RD_CLK).extract(i, 1)); -					dff_cell->setPort(ID::Q, rd_signals.back()); -					count_dff++; - -					RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$d"), mem_width); - -					rd_signals.clear(); -					rd_signals.push_back(RTLIL::SigSpec(w)); -					dff_cell->setPort(ID::D, rd_signals.back()); -				} - -				SigBit en_bit = cell->getPort(ID::RD_EN).extract(i); -				if (en_bit != State::S1) { -					SigSpec new_d = module->Mux(genid(cell->name, "$rdenmux", i), -							dff_cell->getPort(ID::Q), dff_cell->getPort(ID::D), en_bit); -					dff_cell->setPort(ID::D, new_d); -				} -			} +			rd_signals.push_back(port.data); -			for (int j = 0; j < mem_abits; j++) +			for (int j = 0; j < abits; j++)  			{  				std::vector<RTLIL::SigSpec> next_rd_signals;  				for (size_t k = 0; k < rd_signals.size(); k++)  				{ -					RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdmux", i, "", j, "", k), ID($mux)); -					c->parameters[ID::WIDTH] = cell->parameters[ID::WIDTH]; +					RTLIL::Cell *c = module->addCell(genid(mem.memid, "$rdmux", i, "", j, "", k), ID($mux)); +					c->parameters[ID::WIDTH] = mem.width;  					c->setPort(ID::Y, rd_signals[k]); -					c->setPort(ID::S, rd_addr.extract(mem_abits-j-1, 1)); +					c->setPort(ID::S, rd_addr.extract(abits-j-1, 1));  					count_mux++; -					c->setPort(ID::A, module->addWire(genid(cell->name, "$rdmux", i, "", j, "", k, "$a"), mem_width)); -					c->setPort(ID::B, module->addWire(genid(cell->name, "$rdmux", i, "", j, "", k, "$b"), mem_width)); +					c->setPort(ID::A, module->addWire(genid(mem.memid, "$rdmux", i, "", j, "", k, "$a"), mem.width)); +					c->setPort(ID::B, module->addWire(genid(mem.memid, "$rdmux", i, "", j, "", k, "$b"), mem.width));  					next_rd_signals.push_back(c->getPort(ID::A));  					next_rd_signals.push_back(c->getPort(ID::B)); @@ -313,38 +261,37 @@ struct MemoryMapWorker  				next_rd_signals.swap(rd_signals);  			} -			for (int j = 0; j < mem_size; j++) +			for (int j = 0; j < mem.size; j++)  				module->connect(RTLIL::SigSig(rd_signals[j], data_reg_out[j]));  		}  		log("  read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux); -		for (int i = 0; i < mem_size; i++) +		for (int i = 0; i < mem.size; i++)  		{  			if (static_cells_map.count(i) > 0)  				continue;  			RTLIL::SigSpec sig = data_reg_out[i]; -			for (int j = 0; j < cell->parameters[ID::WR_PORTS].as_int(); j++) +			for (int j = 0; j < GetSize(mem.wr_ports); j++)  			{ -				RTLIL::SigSpec wr_addr = cell->getPort(ID::WR_ADDR).extract(j*mem_abits, mem_abits); -				RTLIL::SigSpec wr_data = cell->getPort(ID::WR_DATA).extract(j*mem_width, mem_width); -				RTLIL::SigSpec wr_en = cell->getPort(ID::WR_EN).extract(j*mem_width, mem_width); +				auto &port = mem.wr_ports[j]; +				RTLIL::SigSpec wr_addr = port.addr; -				if (mem_offset) -					wr_addr = module->Sub(NEW_ID, wr_addr, SigSpec(mem_offset, GetSize(wr_addr))); +				if (mem.start_offset) +					wr_addr = module->Sub(NEW_ID, wr_addr, SigSpec(mem.start_offset, GetSize(wr_addr))); -				RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i, mem_abits)); +				RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i, GetSize(wr_addr)));  				int wr_offset = 0; -				while (wr_offset < wr_en.size()) +				while (wr_offset < port.en.size())  				{  					int wr_width = 1; -					RTLIL::SigSpec wr_bit = wr_en.extract(wr_offset, 1); +					RTLIL::SigSpec wr_bit = port.en.extract(wr_offset, 1); -					while (wr_offset + wr_width < wr_en.size()) { -						RTLIL::SigSpec next_wr_bit = wr_en.extract(wr_offset + wr_width, 1); +					while (wr_offset + wr_width < port.en.size()) { +						RTLIL::SigSpec next_wr_bit = port.en.extract(wr_offset + wr_width, 1);  						if (next_wr_bit != wr_bit)  							break;  						wr_width++; @@ -354,7 +301,7 @@ struct MemoryMapWorker  					if (wr_bit != State::S1)  					{ -						RTLIL::Cell *c = module->addCell(genid(cell->name, "$wren", i, "", j, "", wr_offset), ID($and)); +						RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", i, "", j, "", wr_offset), ID($and));  						c->parameters[ID::A_SIGNED] = RTLIL::Const(0);  						c->parameters[ID::B_SIGNED] = RTLIL::Const(0);  						c->parameters[ID::A_WIDTH] = RTLIL::Const(1); @@ -363,17 +310,17 @@ struct MemoryMapWorker  						c->setPort(ID::A, w);  						c->setPort(ID::B, wr_bit); -						w = module->addWire(genid(cell->name, "$wren", i, "", j, "", wr_offset, "$y")); +						w = module->addWire(genid(mem.memid, "$wren", i, "", j, "", wr_offset, "$y"));  						c->setPort(ID::Y, RTLIL::SigSpec(w));  					} -					RTLIL::Cell *c = module->addCell(genid(cell->name, "$wrmux", i, "", j, "", wr_offset), ID($mux)); +					RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", i, "", j, "", wr_offset), ID($mux));  					c->parameters[ID::WIDTH] = wr_width;  					c->setPort(ID::A, sig.extract(wr_offset, wr_width)); -					c->setPort(ID::B, wr_data.extract(wr_offset, wr_width)); +					c->setPort(ID::B, port.data.extract(wr_offset, wr_width));  					c->setPort(ID::S, RTLIL::SigSpec(w)); -					w = module->addWire(genid(cell->name, "$wrmux", i, "", j, "", wr_offset, "$y"), wr_width); +					w = module->addWire(genid(mem.memid, "$wrmux", i, "", j, "", wr_offset, "$y"), wr_width);  					c->setPort(ID::Y, w);  					sig.replace(wr_offset, w); @@ -387,17 +334,13 @@ struct MemoryMapWorker  		log("  write interface: %d write mux blocks.\n", count_wrmux); -		module->remove(cell); +		mem.remove();  	}  	void run()  	{ -		std::vector<RTLIL::Cell*> cells; -		for (auto cell : module->selected_cells()) -			if (cell->type == ID($mem)) -				cells.push_back(cell); -		for (auto cell : cells) -			handle_cell(cell); +		for (auto &mem : Mem::get_selected_memories(module)) +			handle_memory(mem);  	}  }; @@ -430,7 +373,7 @@ struct MemoryMapPass : public Pass {  		bool attr_icase = false;  		dict<RTLIL::IdString, std::vector<RTLIL::Const>> attributes; -		log_header(design, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n"); +		log_header(design, "Executing MEMORY_MAP pass (converting memories to logic and flip-flops).\n");  		size_t argidx;  		for (argidx = 1; argidx < args.size(); argidx++) diff --git a/passes/memory/memory_nordff.cc b/passes/memory/memory_nordff.cc index 07bbd9fe8..a4fdcfc38 100644 --- a/passes/memory/memory_nordff.cc +++ b/passes/memory/memory_nordff.cc @@ -19,6 +19,7 @@  #include "kernel/yosys.h"  #include "kernel/sigtools.h" +#include "kernel/mem.h"  USING_YOSYS_NAMESPACE  PRIVATE_NAMESPACE_BEGIN @@ -37,7 +38,7 @@ struct MemoryNordffPass : public Pass {  	}  	void execute(std::vector<std::string> args, RTLIL::Design *design) override  	{ -		log_header(design, "Executing MEMORY_NORDFF pass (extracting $dff cells from $mem).\n"); +		log_header(design, "Executing MEMORY_NORDFF pass (extracting $dff cells from memories).\n");  		size_t argidx;  		for (argidx = 1; argidx < args.size(); argidx++) { @@ -50,70 +51,15 @@ struct MemoryNordffPass : public Pass {  		extra_args(args, argidx, design);  		for (auto module : design->selected_modules()) -		for (auto cell : vector<Cell*>(module->selected_cells())) +		for (auto &mem : Mem::get_selected_memories(module))  		{ -			if (cell->type != ID($mem)) -				continue; +			bool changed = false; +			for (int i = 0; i < GetSize(mem.rd_ports); i++) +				if (mem.extract_rdff(i)) +					changed = true; -			int rd_ports = cell->getParam(ID::RD_PORTS).as_int(); -			int abits = cell->getParam(ID::ABITS).as_int(); -			int width = cell->getParam(ID::WIDTH).as_int(); - -			SigSpec rd_addr = cell->getPort(ID::RD_ADDR); -			SigSpec rd_data = cell->getPort(ID::RD_DATA); -			SigSpec rd_clk = cell->getPort(ID::RD_CLK); -			SigSpec rd_en = cell->getPort(ID::RD_EN); -			Const rd_clk_enable = cell->getParam(ID::RD_CLK_ENABLE); -			Const rd_clk_polarity = cell->getParam(ID::RD_CLK_POLARITY); - -			for (int i = 0; i < rd_ports; i++) -			{ -				bool clk_enable = rd_clk_enable[i] == State::S1; - -				if (clk_enable) -				{ -					bool clk_polarity = cell->getParam(ID::RD_CLK_POLARITY)[i] == State::S1; -					bool transparent = cell->getParam(ID::RD_TRANSPARENT)[i] == State::S1; - -					SigSpec clk = cell->getPort(ID::RD_CLK)[i] ; -					SigSpec en = cell->getPort(ID::RD_EN)[i]; -					Cell *c; - -					if (transparent) -					{ -						SigSpec sig_q = module->addWire(NEW_ID, abits); -						SigSpec sig_d = rd_addr.extract(abits * i, abits); -						rd_addr.replace(abits * i, sig_q); -						if (en != State::S1) -							sig_d = module->Mux(NEW_ID, sig_q, sig_d, en); -						c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity); -					} -					else -					{ -						SigSpec sig_d = module->addWire(NEW_ID, width); -						SigSpec sig_q = rd_data.extract(width * i, width); -						rd_data.replace(width *i, sig_d); -						if (en != State::S1) -							sig_d = module->Mux(NEW_ID, sig_q, sig_d, en); -						c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity); -					} - -					log("Extracted %s FF from read port %d of %s.%s: %s\n", transparent ? "addr" : "data", -							i, log_id(module), log_id(cell), log_id(c)); -				} - -				rd_en[i] = State::S1; -				rd_clk[i] = State::S0; -				rd_clk_enable[i] = State::S0; -				rd_clk_polarity[i] = State::S1; -			} - -			cell->setPort(ID::RD_ADDR, rd_addr); -			cell->setPort(ID::RD_DATA, rd_data); -			cell->setPort(ID::RD_CLK, rd_clk); -			cell->setPort(ID::RD_EN, rd_en); -			cell->setParam(ID::RD_CLK_ENABLE, rd_clk_enable); -			cell->setParam(ID::RD_CLK_POLARITY, rd_clk_polarity); +			if (changed) +				mem.emit();  		}  	}  } MemoryNordffPass; diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc index d04d4ba7a..16b57d9c3 100644 --- a/passes/memory/memory_unpack.cc +++ b/passes/memory/memory_unpack.cc @@ -17,114 +17,12 @@   *   */ -#include "kernel/register.h" -#include "kernel/log.h" -#include <sstream> -#include <algorithm> -#include <stdlib.h> +#include "kernel/yosys.h" +#include "kernel/mem.h"  USING_YOSYS_NAMESPACE  PRIVATE_NAMESPACE_BEGIN -void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory) -{ -	log("Creating $memrd and $memwr for memory `%s' in module `%s':\n", -			memory->name.c_str(), module->name.c_str()); - -	RTLIL::IdString mem_name = RTLIL::escape_id(memory->parameters.at(ID::MEMID).decode_string()); - -	while (module->memories.count(mem_name) != 0) -		mem_name = mem_name.str() + stringf("_%d", autoidx++); - -	RTLIL::Memory *mem = new RTLIL::Memory; -	mem->name = mem_name; -	mem->width = memory->parameters.at(ID::WIDTH).as_int(); -	mem->start_offset = memory->parameters.at(ID::OFFSET).as_int(); -	mem->size = memory->parameters.at(ID::SIZE).as_int(); -	module->memories[mem_name] = mem; - -	int abits = memory->parameters.at(ID::ABITS).as_int(); -	int num_rd_ports = memory->parameters.at(ID::RD_PORTS).as_int(); -	int num_wr_ports = memory->parameters.at(ID::WR_PORTS).as_int(); - -	for (int i = 0; i < num_rd_ports; i++) -	{ -		RTLIL::Cell *cell = module->addCell(NEW_ID, ID($memrd)); -		cell->parameters[ID::MEMID] = mem_name.str(); -		cell->parameters[ID::ABITS] = memory->parameters.at(ID::ABITS); -		cell->parameters[ID::WIDTH] = memory->parameters.at(ID::WIDTH); -		cell->parameters[ID::CLK_ENABLE] = RTLIL::SigSpec(memory->parameters.at(ID::RD_CLK_ENABLE)).extract(i, 1).as_const(); -		cell->parameters[ID::CLK_POLARITY] = RTLIL::SigSpec(memory->parameters.at(ID::RD_CLK_POLARITY)).extract(i, 1).as_const(); -		cell->parameters[ID::TRANSPARENT] = RTLIL::SigSpec(memory->parameters.at(ID::RD_TRANSPARENT)).extract(i, 1).as_const(); -		cell->setPort(ID::CLK, memory->getPort(ID::RD_CLK).extract(i, 1)); -		cell->setPort(ID::EN, memory->getPort(ID::RD_EN).extract(i, 1)); -		cell->setPort(ID::ADDR, memory->getPort(ID::RD_ADDR).extract(i*abits, abits)); -		cell->setPort(ID::DATA, memory->getPort(ID::RD_DATA).extract(i*mem->width, mem->width)); -	} - -	for (int i = 0; i < num_wr_ports; i++) -	{ -		RTLIL::Cell *cell = module->addCell(NEW_ID, ID($memwr)); -		cell->parameters[ID::MEMID] = mem_name.str(); -		cell->parameters[ID::ABITS] = memory->parameters.at(ID::ABITS); -		cell->parameters[ID::WIDTH] = memory->parameters.at(ID::WIDTH); -		cell->parameters[ID::CLK_ENABLE] = RTLIL::SigSpec(memory->parameters.at(ID::WR_CLK_ENABLE)).extract(i, 1).as_const(); -		cell->parameters[ID::CLK_POLARITY] = RTLIL::SigSpec(memory->parameters.at(ID::WR_CLK_POLARITY)).extract(i, 1).as_const(); -		cell->parameters[ID::PRIORITY] = i; -		cell->setPort(ID::CLK, memory->getPort(ID::WR_CLK).extract(i, 1)); -		cell->setPort(ID::EN, memory->getPort(ID::WR_EN).extract(i*mem->width, mem->width)); -		cell->setPort(ID::ADDR, memory->getPort(ID::WR_ADDR).extract(i*abits, abits)); -		cell->setPort(ID::DATA, memory->getPort(ID::WR_DATA).extract(i*mem->width, mem->width)); -	} - -	Const initval = memory->parameters.at(ID::INIT); -	RTLIL::Cell *last_init_cell = nullptr; -	SigSpec last_init_data; -	int last_init_addr=0; - -	for (int i = 0; i < GetSize(initval) && i/mem->width < (1 << abits); i += mem->width) { -		Const val = initval.extract(i, mem->width, State::Sx); -		for (auto bit : val.bits) -			if (bit != State::Sx) -				goto found_non_undef_initval; -		continue; -	found_non_undef_initval: -		if (last_init_cell && last_init_addr+1 == i/mem->width) { -			last_init_cell->parameters[ID::WORDS] = last_init_cell->parameters[ID::WORDS].as_int() + 1; -			last_init_data.append(val); -			last_init_addr++; -		} else { -			if (last_init_cell) -				last_init_cell->setPort(ID::DATA, last_init_data); -			RTLIL::Cell *cell = module->addCell(NEW_ID, ID($meminit)); -			cell->parameters[ID::MEMID] = mem_name.str(); -			cell->parameters[ID::ABITS] = memory->parameters.at(ID::ABITS); -			cell->parameters[ID::WIDTH] = memory->parameters.at(ID::WIDTH); -			cell->parameters[ID::WORDS] = 1; -			cell->parameters[ID::PRIORITY] = i/mem->width; -			cell->setPort(ID::ADDR, SigSpec(i/mem->width, abits)); -			last_init_cell = cell; -			last_init_addr = i/mem->width; -			last_init_data = val; -		} -	} - -	if (last_init_cell) -		last_init_cell->setPort(ID::DATA, last_init_data); - -	module->remove(memory); -} - -void handle_module(RTLIL::Design *design, RTLIL::Module *module) -{ -	std::vector<RTLIL::IdString> memcells; -	for (auto cell : module->cells()) -		if (cell->type == ID($mem) && design->selected(module, cell)) -			memcells.push_back(cell->name); -	for (auto &it : memcells) -		handle_memory(module, module->cell(it)); -} -  struct MemoryUnpackPass : public Pass {  	MemoryUnpackPass() : Pass("memory_unpack", "unpack multi-port memory cells") { }  	void help() override @@ -140,8 +38,14 @@ struct MemoryUnpackPass : public Pass {  	void execute(std::vector<std::string> args, RTLIL::Design *design) override {  		log_header(design, "Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");  		extra_args(args, 1, design); -		for (auto module : design->selected_modules()) -			handle_module(design, module); +		for (auto module : design->selected_modules()) { +			for (auto &mem : Mem::get_selected_memories(module)) { +				if (mem.packed) { +					mem.packed = false; +					mem.emit(); +				} +			} +		}  	}  } MemoryUnpackPass; diff --git a/passes/opt/opt_mem.cc b/passes/opt/opt_mem.cc index 24df1356b..49a0ac51a 100644 --- a/passes/opt/opt_mem.cc +++ b/passes/opt/opt_mem.cc @@ -19,82 +19,11 @@  #include "kernel/yosys.h"  #include "kernel/sigtools.h" +#include "kernel/mem.h"  USING_YOSYS_NAMESPACE  PRIVATE_NAMESPACE_BEGIN -struct OptMemWorker -{ -	RTLIL::Design *design; -	RTLIL::Module *module; -	SigMap sigmap; -	bool restart; - -	dict<IdString, vector<IdString>> memrd, memwr, meminit; -	pool<IdString> remove_mem, remove_cells; - -	OptMemWorker(RTLIL::Module *module) : design(module->design), module(module), sigmap(module), restart(false) -	{ -		for (auto &it : module->memories) -		{ -			memrd[it.first]; -			memwr[it.first]; -			meminit[it.first]; -		} - -		for (auto cell : module->cells()) -		{ -			if (cell->type == ID($memrd)) { -				IdString id = cell->getParam(ID::MEMID).decode_string(); -				memrd.at(id).push_back(cell->name); -			} - -			if (cell->type == ID($memwr)) { -				IdString id = cell->getParam(ID::MEMID).decode_string(); -				memwr.at(id).push_back(cell->name); -			} - -			if (cell->type == ID($meminit)) { -				IdString id = cell->getParam(ID::MEMID).decode_string(); -				meminit.at(id).push_back(cell->name); -			} -		} -	} - -	~OptMemWorker() -	{ -		for (auto it : remove_mem) -		{ -			for (auto cell_name : memrd[it]) -				module->remove(module->cell(cell_name)); -			for (auto cell_name : memwr[it]) -				module->remove(module->cell(cell_name)); -			for (auto cell_name : meminit[it]) -				module->remove(module->cell(cell_name)); - -			delete module->memories.at(it); -			module->memories.erase(it); -		} - -		for (auto cell_name : remove_cells) -			module->remove(module->cell(cell_name)); -	} - -	int run(RTLIL::Memory *mem) -	{ -		if (restart || remove_mem.count(mem->name)) -			return 0; - -		if (memwr.at(mem->name).empty() && meminit.at(mem->name).empty()) { -			log("Removing memory %s.%s with no write ports or init data.\n", log_id(module), log_id(mem)); -			remove_mem.insert(mem->name); -			return 1; -		} - -		return 0; -	} -}; -  struct OptMemPass : public Pass {  	OptMemPass() : Pass("opt_mem", "optimize memories") { }  	void help() override @@ -122,15 +51,11 @@ struct OptMemPass : public Pass {  		int total_count = 0;  		for (auto module : design->selected_modules()) { -			while (1) { -				int cnt = 0; -				OptMemWorker worker(module); -				for (auto &it : module->memories) -					if (module->selected(it.second)) -						cnt += worker.run(it.second); -				if (!cnt && !worker.restart) -					break; -				total_count += cnt; +			for (auto &mem : Mem::get_selected_memories(module)) { +				if (mem.wr_ports.empty() && mem.inits.empty()) { +					mem.remove(); +					total_count++; +				}  			}  		} diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc index 2cb91c009..cbf7c5435 100644 --- a/passes/sat/clk2fflogic.cc +++ b/passes/sat/clk2fflogic.cc @@ -21,6 +21,7 @@  #include "kernel/sigtools.h"  #include "kernel/ffinit.h"  #include "kernel/ff.h" +#include "kernel/mem.h"  USING_YOSYS_NAMESPACE  PRIVATE_NAMESPACE_BEGIN @@ -84,89 +85,65 @@ struct Clk2fflogicPass : public Pass {  			SigMap sigmap(module);  			FfInitVals initvals(&sigmap, module); -			for (auto cell : vector<Cell*>(module->selected_cells())) +			for (auto &mem : Mem::get_selected_memories(module))  			{ -				if (cell->type.in(ID($mem))) -				{ -					int abits = cell->getParam(ID::ABITS).as_int(); -					int width = cell->getParam(ID::WIDTH).as_int(); -					int rd_ports = cell->getParam(ID::RD_PORTS).as_int(); -					int wr_ports = cell->getParam(ID::WR_PORTS).as_int(); - -					for (int i = 0; i < rd_ports; i++) { -						if (cell->getParam(ID::RD_CLK_ENABLE).extract(i).as_bool()) -							log_error("Read port %d of memory %s.%s is clocked. This is not supported by \"clk2fflogic\"! " -									"Call \"memory\" with -nordff to avoid this error.\n", i, log_id(cell), log_id(module)); -					} - -					Const wr_clk_en_param = cell->getParam(ID::WR_CLK_ENABLE); -					Const wr_clk_pol_param = cell->getParam(ID::WR_CLK_POLARITY); - -					SigSpec wr_clk_port = cell->getPort(ID::WR_CLK); -					SigSpec wr_en_port = cell->getPort(ID::WR_EN); -					SigSpec wr_addr_port = cell->getPort(ID::WR_ADDR); -					SigSpec wr_data_port = cell->getPort(ID::WR_DATA); - -					for (int wport = 0; wport < wr_ports; wport++) -					{ -						bool clken = wr_clk_en_param[wport] == State::S1; -						bool clkpol = wr_clk_pol_param[wport] == State::S1; - -						if (!clken) -							continue; - -						SigBit clk = wr_clk_port[wport]; -						SigSpec en = wr_en_port.extract(wport*width, width); -						SigSpec addr = wr_addr_port.extract(wport*abits, abits); -						SigSpec data = wr_data_port.extract(wport*width, width); +				for (int i = 0; i < GetSize(mem.rd_ports); i++) { +					auto &port = mem.rd_ports[i]; +					if (port.clk_enable) +						log_error("Read port %d of memory %s.%s is clocked. This is not supported by \"clk2fflogic\"! " +								"Call \"memory\" with -nordff to avoid this error.\n", i, log_id(mem.memid), log_id(module)); +				} -						log("Modifying write port %d on memory %s.%s: CLK=%s, A=%s, D=%s\n", -								wport, log_id(module), log_id(cell), log_signal(clk), -								log_signal(addr), log_signal(data)); +				for (int i = 0; i < GetSize(mem.wr_ports); i++) +				{ +					auto &port = mem.wr_ports[i]; -						Wire *past_clk = module->addWire(NEW_ID); -						past_clk->attributes[ID::init] = clkpol ? State::S1 : State::S0; -						module->addFf(NEW_ID, clk, past_clk); +					if (!port.clk_enable) +						continue; -						SigSpec clock_edge_pattern; +					log("Modifying write port %d on memory %s.%s: CLK=%s, A=%s, D=%s\n", +							i, log_id(module), log_id(mem.memid), log_signal(port.clk), +							log_signal(port.addr), log_signal(port.data)); -						if (clkpol) { -							clock_edge_pattern.append(State::S0); -							clock_edge_pattern.append(State::S1); -						} else { -							clock_edge_pattern.append(State::S1); -							clock_edge_pattern.append(State::S0); -						} +					Wire *past_clk = module->addWire(NEW_ID); +					past_clk->attributes[ID::init] = port.clk_polarity ? State::S1 : State::S0; +					module->addFf(NEW_ID, port.clk, past_clk); -						SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern); +					SigSpec clock_edge_pattern; -						SigSpec en_q = module->addWire(NEW_ID, GetSize(en)); -						module->addFf(NEW_ID, en, en_q); +					if (port.clk_polarity) { +						clock_edge_pattern.append(State::S0); +						clock_edge_pattern.append(State::S1); +					} else { +						clock_edge_pattern.append(State::S1); +						clock_edge_pattern.append(State::S0); +					} -						SigSpec addr_q = module->addWire(NEW_ID, GetSize(addr)); -						module->addFf(NEW_ID, addr, addr_q); +					SigSpec clock_edge = module->Eqx(NEW_ID, {port.clk, SigSpec(past_clk)}, clock_edge_pattern); -						SigSpec data_q = module->addWire(NEW_ID, GetSize(data)); -						module->addFf(NEW_ID, data, data_q); +					SigSpec en_q = module->addWire(NEW_ID, GetSize(port.en)); +					module->addFf(NEW_ID, port.en, en_q); -						wr_clk_port[wport] = State::S0; -						wr_en_port.replace(wport*width, module->Mux(NEW_ID, Const(0, GetSize(en_q)), en_q, clock_edge)); -						wr_addr_port.replace(wport*abits, addr_q); -						wr_data_port.replace(wport*width, data_q); +					SigSpec addr_q = module->addWire(NEW_ID, GetSize(port.addr)); +					module->addFf(NEW_ID, port.addr, addr_q); -						wr_clk_en_param[wport] = State::S0; -						wr_clk_pol_param[wport] = State::S0; -					} +					SigSpec data_q = module->addWire(NEW_ID, GetSize(port.data)); +					module->addFf(NEW_ID, port.data, data_q); -					cell->setParam(ID::WR_CLK_ENABLE, wr_clk_en_param); -					cell->setParam(ID::WR_CLK_POLARITY, wr_clk_pol_param); +					port.clk = State::S0; +					port.en = module->Mux(NEW_ID, Const(0, GetSize(en_q)), en_q, clock_edge); +					port.addr = addr_q; +					port.data = data_q; -					cell->setPort(ID::WR_CLK, wr_clk_port); -					cell->setPort(ID::WR_EN, wr_en_port); -					cell->setPort(ID::WR_ADDR, wr_addr_port); -					cell->setPort(ID::WR_DATA, wr_data_port); +					port.clk_enable = false; +					port.clk_polarity = false;  				} +				mem.emit(); +			} + +			for (auto cell : vector<Cell*>(module->selected_cells())) +			{  				SigSpec qval;  				if (RTLIL::builtin_ff_cell_types().count(cell->type)) {  					FfData ff(&initvals, cell); diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 3d2081a74..75f922dba 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -20,6 +20,7 @@  #include "kernel/yosys.h"  #include "kernel/sigtools.h"  #include "kernel/celltypes.h" +#include "kernel/mem.h"  #include <ctime> @@ -64,6 +65,7 @@ struct SimInstance  	pool<SigBit> dirty_bits;  	pool<Cell*> dirty_cells; +	pool<IdString> dirty_memories;  	pool<SimInstance*, hash_ptr_ops> dirty_children;  	struct ff_state_t @@ -74,16 +76,20 @@ struct SimInstance  	struct mem_state_t  	{ -		Const past_wr_clk; -		Const past_wr_en; -		Const past_wr_addr; -		Const past_wr_data; +		Mem *mem; +		std::vector<Const> past_wr_clk; +		std::vector<Const> past_wr_en; +		std::vector<Const> past_wr_addr; +		std::vector<Const> past_wr_data;  		Const data;  	};  	dict<Cell*, ff_state_t> ff_database; -	dict<Cell*, mem_state_t> mem_database; +	dict<IdString, mem_state_t> mem_database;  	pool<Cell*> formal_database; +	dict<Cell*, IdString> mem_cells; + +	std::vector<Mem> memories;  	dict<Wire*, pair<int, Const>> vcd_database; @@ -120,6 +126,19 @@ struct SimInstance  			}  		} +		memories = Mem::get_all_memories(module); +		for (auto &mem : memories) { +			auto &mdb = mem_database[mem.memid]; +			mdb.mem = &mem; +			for (auto &port : mem.wr_ports) { +				mdb.past_wr_clk.push_back(Const(State::Sx)); +				mdb.past_wr_en.push_back(Const(State::Sx, GetSize(port.en))); +				mdb.past_wr_addr.push_back(Const(State::Sx, GetSize(port.addr))); +				mdb.past_wr_data.push_back(Const(State::Sx, GetSize(port.data))); +			} +			mdb.data = mem.get_init_data(); +		} +  		for (auto cell : module->cells())  		{  			Module *mod = module->design->module(cell->type); @@ -145,29 +164,9 @@ struct SimInstance  				ff_database[cell] = ff;  			} -			if (cell->type == ID($mem)) +			if (cell->type.in(ID($mem), ID($meminit), ID($memwr), ID($memrd)))  			{ -				mem_state_t mem; - -				mem.past_wr_clk = Const(State::Sx, GetSize(cell->getPort(ID::WR_CLK))); -				mem.past_wr_en = Const(State::Sx, GetSize(cell->getPort(ID::WR_EN))); -				mem.past_wr_addr = Const(State::Sx, GetSize(cell->getPort(ID::WR_ADDR))); -				mem.past_wr_data = Const(State::Sx, GetSize(cell->getPort(ID::WR_DATA))); - -				mem.data = cell->getParam(ID::INIT); -				int sz = cell->getParam(ID::SIZE).as_int() * cell->getParam(ID::WIDTH).as_int(); - -				if (GetSize(mem.data) > sz) -					mem.data.bits.resize(sz); - -				while (GetSize(mem.data) < sz) -					mem.data.bits.push_back(State::Sx); - -				mem_database[cell] = mem; -			} -			if (cell->type.in(ID($memwr),ID($memrd))) -			{ -				log_error("$memrd and $memwr cells have to be merged to stand-alone $mem cells (execute memory_collect pass)\n"); +				mem_cells[cell] = cell->parameters.at(ID::MEMID).decode_string();  			}  			if (cell->type.in(ID($assert), ID($cover), ID($assume))) {  				formal_database.insert(cell); @@ -190,7 +189,8 @@ struct SimInstance  			for (auto &it : mem_database) {  				mem_state_t &mem = it.second; -				zinit(mem.past_wr_en); +				for (auto &val : mem.past_wr_en) +					zinit(val);  				zinit(mem.data);  			}  		} @@ -261,37 +261,9 @@ struct SimInstance  		if (formal_database.count(cell))  			return; -		if (mem_database.count(cell)) +		if (mem_cells.count(cell))  		{ -			mem_state_t &mem = mem_database.at(cell); - -			int num_rd_ports = cell->getParam(ID::RD_PORTS).as_int(); - -			int size = cell->getParam(ID::SIZE).as_int(); -			int offset = cell->getParam(ID::OFFSET).as_int(); -			int abits = cell->getParam(ID::ABITS).as_int(); -			int width = cell->getParam(ID::WIDTH).as_int(); - -			if (cell->getParam(ID::RD_CLK_ENABLE).as_bool()) -				log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(cell)); - -			SigSpec rd_addr_sig = cell->getPort(ID::RD_ADDR); -			SigSpec rd_data_sig = cell->getPort(ID::RD_DATA); - -			for (int port_idx = 0; port_idx < num_rd_ports; port_idx++) -			{ -				Const addr = get_state(rd_addr_sig.extract(port_idx*abits, abits)); -				Const data = Const(State::Sx, width); - -				if (addr.is_fully_def()) { -					int index = addr.as_int() - offset; -					if (index >= 0 && index < size) -						data = mem.data.extract(index*width, width); -				} - -				set_state(rd_data_sig.extract(port_idx*width, width), data); -			} - +			dirty_memories.insert(mem_cells[cell]);  			return;  		} @@ -354,6 +326,29 @@ struct SimInstance  		log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));  	} +	void update_memory(IdString id) { +		auto &mdb = mem_database[id]; +		auto &mem = *mdb.mem; + +		for (int port_idx = 0; port_idx < GetSize(mem.rd_ports); port_idx++) +		{ +			auto &port = mem.rd_ports[port_idx]; +			Const addr = get_state(port.addr); +			Const data = Const(State::Sx, mem.width); + +			if (port.clk_enable) +				log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(mem.memid)); + +			if (addr.is_fully_def()) { +				int index = addr.as_int() - mem.start_offset; +				if (index >= 0 && index < mem.size) +					data = mdb.data.extract(index*mem.width, mem.width); +			} + +			set_state(port.data, data); +		} +	} +  	void update_ph1()  	{  		pool<Cell*> queue_cells; @@ -385,6 +380,10 @@ struct SimInstance  				continue;  			} +			for (auto &memid : dirty_memories) +				update_memory(memid); +			dirty_memories.clear(); +  			for (auto wire : queue_outports)  				if (instance->hasPort(wire->name)) {  					Const value = get_state(wire); @@ -428,50 +427,40 @@ struct SimInstance  		for (auto &it : mem_database)  		{ -			Cell *cell = it.first; -			mem_state_t &mem = it.second; - -			int num_wr_ports = cell->getParam(ID::WR_PORTS).as_int(); - -			int size = cell->getParam(ID::SIZE).as_int(); -			int offset = cell->getParam(ID::OFFSET).as_int(); -			int abits = cell->getParam(ID::ABITS).as_int(); -			int width = cell->getParam(ID::WIDTH).as_int(); +			mem_state_t &mdb = it.second; +			auto &mem = *mdb.mem; -			Const wr_clk_enable = cell->getParam(ID::WR_CLK_ENABLE); -			Const wr_clk_polarity = cell->getParam(ID::WR_CLK_POLARITY); -			Const current_wr_clk  = get_state(cell->getPort(ID::WR_CLK)); - -			for (int port_idx = 0; port_idx < num_wr_ports; port_idx++) +			for (int port_idx = 0; port_idx < GetSize(mem.wr_ports); port_idx++)  			{ +				auto &port = mem.wr_ports[port_idx];  				Const addr, data, enable; -				if (wr_clk_enable[port_idx] == State::S0) +				if (!port.clk_enable)  				{ -					addr = get_state(cell->getPort(ID::WR_ADDR).extract(port_idx*abits, abits)); -					data = get_state(cell->getPort(ID::WR_DATA).extract(port_idx*width, width)); -					enable = get_state(cell->getPort(ID::WR_EN).extract(port_idx*width, width)); +					addr = get_state(port.addr); +					data = get_state(port.data); +					enable = get_state(port.en);  				}  				else  				{ -					if (wr_clk_polarity[port_idx] == State::S1 ? -							(mem.past_wr_clk[port_idx] == State::S1 || current_wr_clk[port_idx] != State::S1) : -							(mem.past_wr_clk[port_idx] == State::S0 || current_wr_clk[port_idx] != State::S0)) +					if (port.clk_polarity ? +							(mdb.past_wr_clk[port_idx] == State::S1 || get_state(port.clk) != State::S1) : +							(mdb.past_wr_clk[port_idx] == State::S0 || get_state(port.clk) != State::S0))  						continue; -					addr = mem.past_wr_addr.extract(port_idx*abits, abits); -					data = mem.past_wr_data.extract(port_idx*width, width); -					enable = mem.past_wr_en.extract(port_idx*width, width); +					addr = mdb.past_wr_addr[port_idx]; +					data = mdb.past_wr_data[port_idx]; +					enable = mdb.past_wr_en[port_idx];  				}  				if (addr.is_fully_def())  				{ -					int index = addr.as_int() - offset; -					if (index >= 0 && index < size) -						for (int i = 0; i < width; i++) -							if (enable[i] == State::S1 && mem.data.bits.at(index*width+i) != data[i]) { -								mem.data.bits.at(index*width+i) = data[i]; -								dirty_cells.insert(cell); +					int index = addr.as_int() - mem.start_offset; +					if (index >= 0 && index < mem.size) +						for (int i = 0; i < mem.width; i++) +							if (enable[i] == State::S1 && mdb.data.bits.at(index*mem.width+i) != data[i]) { +								mdb.data.bits.at(index*mem.width+i) = data[i]; +								dirty_memories.insert(mem.memid);  								did_something = true;  							}  				} @@ -502,13 +491,15 @@ struct SimInstance  		for (auto &it : mem_database)  		{ -			Cell *cell = it.first;  			mem_state_t &mem = it.second; -			mem.past_wr_clk  = get_state(cell->getPort(ID::WR_CLK)); -			mem.past_wr_en   = get_state(cell->getPort(ID::WR_EN)); -			mem.past_wr_addr = get_state(cell->getPort(ID::WR_ADDR)); -			mem.past_wr_data = get_state(cell->getPort(ID::WR_DATA)); +			for (int i = 0; i < GetSize(mem.mem->wr_ports); i++) { +				auto &port = mem.mem->wr_ports[i]; +				mem.past_wr_clk[i]  = get_state(port.clk); +				mem.past_wr_en[i]   = get_state(port.en); +				mem.past_wr_addr[i] = get_state(port.addr); +				mem.past_wr_data[i] = get_state(port.data); +			}  		}  		for (auto cell : formal_database) @@ -563,17 +554,13 @@ struct SimInstance  		for (auto &it : mem_database)  		{ -			Cell *cell = it.first;  			mem_state_t &mem = it.second; -			Const initval = mem.data; - -			while (GetSize(initval) >= 2) { -				if (initval[GetSize(initval)-1] != State::Sx) break; -				if (initval[GetSize(initval)-2] != State::Sx) break; -				initval.bits.pop_back(); -			} - -			cell->setParam(ID::INIT, initval); +			mem.mem->clear_inits(); +			MemInit minit; +			minit.addr = mem.mem->start_offset; +			minit.data = mem.data; +			mem.mem->inits.push_back(minit); +			mem.mem->emit();  		}  		for (auto it : children) | 
