mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge pull request #1188 from YosysHQ/eddie/abc9_push_inverters
abc9: push inverters driving box inputs (comb outputs) through $lut soft logic
This commit is contained in:
		
						commit
						5939b5d636
					
				
					 2 changed files with 128 additions and 45 deletions
				
			
		|  | @ -24,12 +24,13 @@ | |||
| 
 | ||||
| #if 0 | ||||
| // Based on &flow3 - better QoR but more experimental
 | ||||
| #define ABC_COMMAND_LUT "&st; &ps -l; "/*"&sweep -v;"*/" &scorr; " \ | ||||
| 						"&st; &if {W}; &save; &st; &syn2; &if {W}; &save; &load; "\ | ||||
| 						"&st; &if -g -K 6; &dch -f; &if {W}; &save; &load; "\ | ||||
| 						"&st; &if -g -K 6; &synch2; &if {W}; &save; &load" | ||||
| #define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \ | ||||
| 						"&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\ | ||||
| 						"&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\ | ||||
| 						"&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\ | ||||
| 						"&mfs; &ps -l" | ||||
| #else | ||||
| #define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps -l; &if {W} {D} -v; &mfs; &ps -l" | ||||
| #define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l" | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
|  | @ -53,6 +54,7 @@ | |||
| #endif | ||||
| 
 | ||||
| #include "frontends/aiger/aigerparse.h" | ||||
| #include "kernel/utils.h" | ||||
| 
 | ||||
| #ifdef YOSYS_LINK_ABC | ||||
| extern "C" int Abc_RealMain(int argc, char *argv[]); | ||||
|  | @ -570,13 +572,23 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 				boxes.emplace_back(cell); | ||||
| 		} | ||||
| 
 | ||||
| 		dict<SigBit, pool<IdString>> bit_drivers, bit_users; | ||||
| 		TopoSort<IdString, RTLIL::sort_by_id_str> toposort; | ||||
| 		dict<RTLIL::Cell*,RTLIL::Cell*> not2drivers; | ||||
| 		dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks; | ||||
| 
 | ||||
| 		std::map<std::string, int> cell_stats; | ||||
| 		for (auto c : mapped_mod->cells()) | ||||
| 		{ | ||||
| 			toposort.node(c->name); | ||||
| 
 | ||||
| 			RTLIL::Cell *cell = nullptr; | ||||
| 			if (c->type == "$_NOT_") { | ||||
| 				RTLIL::SigBit a_bit = c->getPort("\\A").as_bit(); | ||||
| 				RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit(); | ||||
| 				RTLIL::SigBit a_bit = c->getPort("\\A"); | ||||
| 				RTLIL::SigBit y_bit = c->getPort("\\Y"); | ||||
| 				bit_users[a_bit].insert(c->name); | ||||
| 				bit_drivers[y_bit].insert(c->name); | ||||
| 
 | ||||
| 				if (!a_bit.wire) { | ||||
| 					c->setPort("\\Y", module->addWire(NEW_ID)); | ||||
| 					RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); | ||||
|  | @ -584,11 +596,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 					module->connect(RTLIL::SigBit(wire, y_bit.offset), RTLIL::S1); | ||||
| 				} | ||||
| 				else if (!lut_costs.empty() || !lut_file.empty()) { | ||||
| 					RTLIL::Cell* driving_lut = nullptr; | ||||
| 					RTLIL::Cell* driver_lut = nullptr; | ||||
| 					// ABC can return NOT gates that drive POs
 | ||||
| 					if (!a_bit.wire->port_input) { | ||||
| 						// If it's not a NOT gate that that comes from a PI directly,
 | ||||
| 						// find the driving LUT and clone that to guarantee that we won't
 | ||||
| 						// find the driver LUT and clone that to guarantee that we won't
 | ||||
| 						// increase the max logic depth
 | ||||
| 						// (TODO: Optimise by not cloning unless will increase depth)
 | ||||
| 						RTLIL::IdString driver_name; | ||||
|  | @ -596,50 +608,38 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 							driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); | ||||
| 						else | ||||
| 							driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); | ||||
| 						driving_lut = mapped_mod->cell(driver_name); | ||||
| 						driver_lut = mapped_mod->cell(driver_name); | ||||
| 					} | ||||
| 
 | ||||
| 					if (!driving_lut) { | ||||
| 						// If a driver couldn't be found (could be from PI,
 | ||||
| 						// or from a box) then implement using a LUT
 | ||||
| 					if (!driver_lut) { | ||||
| 						// If a driver couldn't be found (could be from PI or box CI)
 | ||||
| 						// then implement using a LUT
 | ||||
| 						cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), | ||||
| 								RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset), | ||||
| 								RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset), | ||||
| 								1); | ||||
| 					} | ||||
| 					else { | ||||
| 						auto driver_a = driving_lut->getPort("\\A").chunks(); | ||||
| 						for (auto &chunk : driver_a) | ||||
| 							chunk.wire = module->wires_[remap_name(chunk.wire->name)]; | ||||
| 						RTLIL::Const driver_lut = driving_lut->getParam("\\LUT"); | ||||
| 						for (auto &b : driver_lut.bits) { | ||||
| 							if (b == RTLIL::State::S0) b = RTLIL::State::S1; | ||||
| 							else if (b == RTLIL::State::S1) b = RTLIL::State::S0; | ||||
| 						} | ||||
| 						cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), | ||||
| 								driver_a, | ||||
| 								RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset), | ||||
| 								driver_lut); | ||||
| 								RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), | ||||
| 								RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), | ||||
| 								RTLIL::Const::from_string("01")); | ||||
| 						bit2sinks[cell->getPort("\\A")].push_back(cell); | ||||
| 						cell_stats["$lut"]++; | ||||
| 					} | ||||
| 					else | ||||
| 						not2drivers[c] = driver_lut; | ||||
| 					continue; | ||||
| 				} | ||||
| 				else { | ||||
| 					cell = module->addCell(remap_name(c->name), "$_NOT_"); | ||||
| 					cell->setPort("\\A", RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset)); | ||||
| 					cell->setPort("\\Y", RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset)); | ||||
| 					cell_stats[RTLIL::unescape_id(c->type)]++; | ||||
| 				} | ||||
| 				else | ||||
| 					log_abort(); | ||||
| 				if (cell && markgroups) cell->attributes["\\abcgroup"] = map_autoidx; | ||||
| 				continue; | ||||
| 			} | ||||
| 			cell_stats[RTLIL::unescape_id(c->type)]++; | ||||
| 
 | ||||
|                         RTLIL::Cell *existing_cell = nullptr; | ||||
| 			RTLIL::Cell *existing_cell = nullptr; | ||||
| 			if (c->type == "$lut") { | ||||
| 				if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) { | ||||
| 					SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]; | ||||
| 					SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]; | ||||
| 				if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT") == RTLIL::Const::from_string("01")) { | ||||
| 					SigSpec my_a = module->wires_.at(remap_name(c->getPort("\\A").as_wire()->name)); | ||||
| 					SigSpec my_y = module->wires_.at(remap_name(c->getPort("\\Y").as_wire()->name)); | ||||
| 					module->connect(my_y, my_a); | ||||
|                                         if (markgroups) c->attributes["\\abcgroup"] = map_autoidx; | ||||
| 					if (markgroups) c->attributes["\\abcgroup"] = map_autoidx; | ||||
| 					log_abort(); | ||||
| 					continue; | ||||
| 				} | ||||
| 				cell = module->addCell(remap_name(c->name), c->type); | ||||
|  | @ -666,10 +666,20 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 						continue; | ||||
| 					//log_assert(c.width == 1);
 | ||||
| 					if (c.wire) | ||||
| 						c.wire = module->wires_[remap_name(c.wire->name)]; | ||||
| 						c.wire = module->wires_.at(remap_name(c.wire->name)); | ||||
| 					newsig.append(c); | ||||
| 				} | ||||
| 				cell->setPort(conn.first, newsig); | ||||
| 
 | ||||
| 				if (cell->input(conn.first)) { | ||||
| 					for (auto i : newsig) | ||||
| 						bit2sinks[i].push_back(cell); | ||||
| 					for (auto i : conn.second) | ||||
| 						bit_users[i].insert(c->name); | ||||
| 				} | ||||
| 				if (cell->output(conn.first)) | ||||
| 					for (auto i : conn.second) | ||||
| 						bit_drivers[i].insert(c->name); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | @ -681,14 +691,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 			if (!conn.first.is_fully_const()) { | ||||
| 				auto chunks = conn.first.chunks(); | ||||
| 				for (auto &c : chunks) | ||||
| 					c.wire = module->wires_[remap_name(c.wire->name)]; | ||||
| 					c.wire = module->wires_.at(remap_name(c.wire->name)); | ||||
| 				conn.first = std::move(chunks); | ||||
| 			} | ||||
| 			if (!conn.second.is_fully_const()) { | ||||
| 				auto chunks = conn.second.chunks(); | ||||
| 				for (auto &c : chunks) | ||||
| 					if (c.wire) | ||||
| 						c.wire = module->wires_[remap_name(c.wire->name)]; | ||||
| 						c.wire = module->wires_.at(remap_name(c.wire->name)); | ||||
| 				conn.second = std::move(chunks); | ||||
| 			} | ||||
| 			module->connect(conn); | ||||
|  | @ -725,6 +735,79 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto &it : bit_users) | ||||
| 			if (bit_drivers.count(it.first)) | ||||
| 				for (auto driver_cell : bit_drivers.at(it.first)) | ||||
| 				for (auto user_cell : it.second) | ||||
| 					toposort.edge(driver_cell, user_cell); | ||||
| 		bool no_loops = toposort.sort(); | ||||
| 		log_assert(no_loops); | ||||
| 
 | ||||
| 		for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { | ||||
| 			RTLIL::Cell *not_cell = mapped_mod->cell(*ii); | ||||
| 			log_assert(not_cell); | ||||
| 			if (not_cell->type != "$_NOT_") | ||||
| 				continue; | ||||
| 			auto it = not2drivers.find(not_cell); | ||||
| 			if (it == not2drivers.end()) | ||||
| 				continue; | ||||
| 			RTLIL::Cell *driver_lut = it->second; | ||||
| 			RTLIL::SigBit a_bit = not_cell->getPort("\\A"); | ||||
| 			RTLIL::SigBit y_bit = not_cell->getPort("\\Y"); | ||||
| 			RTLIL::Const driver_mask; | ||||
| 
 | ||||
| 			a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name)); | ||||
| 			y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name)); | ||||
| 
 | ||||
| 			auto jt = bit2sinks.find(a_bit); | ||||
| 			if (jt == bit2sinks.end()) | ||||
| 				goto clone_lut; | ||||
| 
 | ||||
| 			for (auto sink_cell : jt->second) | ||||
| 				if (sink_cell->type != "$lut") | ||||
| 					goto clone_lut; | ||||
| 
 | ||||
| 			// Push downstream LUTs past inverter
 | ||||
| 			for (auto sink_cell : jt->second) { | ||||
| 				SigSpec A = sink_cell->getPort("\\A"); | ||||
| 				RTLIL::Const mask = sink_cell->getParam("\\LUT"); | ||||
| 				int index = 0; | ||||
| 				for (; index < GetSize(A); index++) | ||||
| 					if (A[index] == a_bit) | ||||
| 						break; | ||||
| 				log_assert(index < GetSize(A)); | ||||
| 				int i = 0; | ||||
| 				while (i < GetSize(mask)) { | ||||
| 					for (int j = 0; j < (1 << index); j++) | ||||
| 						std::swap(mask[i+j], mask[i+j+(1 << index)]); | ||||
| 					i += 1 << (index+1); | ||||
| 				} | ||||
| 				A[index] = y_bit; | ||||
| 				sink_cell->setPort("\\A", A); | ||||
| 				sink_cell->setParam("\\LUT", mask); | ||||
| 			} | ||||
| 
 | ||||
| 			// Since we have rewritten all sinks (which we know
 | ||||
| 			// to be only LUTs) to be after the inverter, we can
 | ||||
| 			// go ahead and clone the LUT with the expectation
 | ||||
| 			// that the original driving LUT will become dangling
 | ||||
| 			// and get cleaned away
 | ||||
| clone_lut: | ||||
| 			driver_mask = driver_lut->getParam("\\LUT"); | ||||
| 			for (auto &b : driver_mask.bits) { | ||||
| 				if (b == RTLIL::State::S0) b = RTLIL::State::S1; | ||||
| 				else if (b == RTLIL::State::S1) b = RTLIL::State::S0; | ||||
| 			} | ||||
| 			auto cell = module->addLut(NEW_ID, | ||||
| 					driver_lut->getPort("\\A"), | ||||
| 					y_bit, | ||||
| 					driver_mask); | ||||
| 			for (auto &bit : cell->connections_.at("\\A")) { | ||||
| 				bit.wire = module->wires_.at(remap_name(bit.wire->name)); | ||||
| 				bit2sinks[bit].push_back(cell); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		//log("ABC RESULTS:        internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
 | ||||
| 		log("ABC RESULTS:           input signals: %8d\n", in_wires); | ||||
| 		log("ABC RESULTS:          output signals: %8d\n", out_wires); | ||||
|  |  | |||
|  | @ -19,6 +19,6 @@ hierarchy -top abc9_test028 | |||
| proc | ||||
| 
 | ||||
| abc9 -lut 4 | ||||
| select -assert-count 1 t:$lut r:LUT=1 r:WIDTH=1 %i %i | ||||
| select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i | ||||
| select -assert-count 1 t:unknown | ||||
| select -assert-none t:$lut t:unknown %% t: %D | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue