mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-26 17:29:23 +00:00 
			
		
		
		
	Fixed edge size cases for signed/unsigned booth generator
This commit is contained in:
		
							parent
							
								
									25a33d4082
								
							
						
					
					
						commit
						411acc4a0a
					
				
					 1 changed files with 128 additions and 53 deletions
				
			
		|  | @ -295,45 +295,85 @@ struct MultPassWorker { | |||
| 						int y_sz = GetSize(B); | ||||
| 						int z_sz = GetSize(Y); | ||||
| 
 | ||||
| 						// create a buffer for each ip
 | ||||
| 						std::string buf_name = "u_mult_multiplicand_buf_"; | ||||
| 						auto A_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); | ||||
| 						A_Buf->setParam(ID::A_WIDTH, x_sz); | ||||
| 						A_Buf->setParam(ID::Y_WIDTH, x_sz); | ||||
| 						A_Buf->setPort(ID::A, SigSpec(A)); | ||||
| 						A_Buf->setParam(ID::A_SIGNED, false); | ||||
| 						// To simplify the generator size the arguments
 | ||||
| 						// to be the same. Then allow logic synthesis to
 | ||||
| 						// clean things up. Size to biggest
 | ||||
| 
 | ||||
| 						std::string wire_name = "u_mult_A"; | ||||
| 						auto A_Wire = module->addWire(new_id(wire_name, __LINE__, ""), x_sz); | ||||
| 						int x_sz_revised = x_sz; | ||||
| 						int y_sz_revised = y_sz; | ||||
| 
 | ||||
| 						A_Buf->setPort(ID::Y, A_Wire); | ||||
| 						if (x_sz != y_sz) { | ||||
| 							if (x_sz < y_sz) { | ||||
| 								if (y_sz % 2 != 0) { | ||||
| 									x_sz_revised = y_sz + 1; | ||||
| 									y_sz_revised = y_sz + 1; | ||||
| 								} else | ||||
| 									x_sz_revised = y_sz; | ||||
| 
 | ||||
| 						buf_name = "u_mult_multiplier_buf_"; | ||||
| 						auto B_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); | ||||
| 						B_Buf->setParam(ID::A_WIDTH, y_sz); | ||||
| 						B_Buf->setParam(ID::Y_WIDTH, y_sz); | ||||
| 						B_Buf->setPort(ID::A, SigSpec(B)); | ||||
| 						B_Buf->setParam(ID::A_SIGNED, false); | ||||
| 								log("Resized x to %d ", x_sz_revised); | ||||
| 							} else { | ||||
| 								if (x_sz % 2 != 0) { | ||||
| 									y_sz_revised = x_sz + 1; | ||||
| 									x_sz_revised = x_sz + 1; | ||||
| 								} else | ||||
| 									y_sz_revised = x_sz; | ||||
| 								log("Resized y to %d ", y_sz_revised); | ||||
| 							} | ||||
| 						} else { | ||||
| 							if (x_sz % 2 != 0) { | ||||
| 								y_sz_revised = y_sz + 1; | ||||
| 								x_sz_revised = x_sz + 1; | ||||
| 							} | ||||
| 						} | ||||
| 
 | ||||
| 						wire_name = "u_mult_B"; | ||||
| 						auto B_Wire = module->addWire(new_id(wire_name, __LINE__, ""), y_sz); | ||||
| 						B_Buf->setPort(ID::Y, B_Wire); | ||||
| 						log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); | ||||
| 
 | ||||
| 						buf_name = "u_mult_result_buf_"; | ||||
| 						auto Z_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); | ||||
| 						Z_Buf->setParam(ID::A_WIDTH, z_sz); | ||||
| 						Z_Buf->setParam(ID::Y_WIDTH, z_sz); | ||||
| 						Z_Buf->setPort(ID::Y, SigSpec(Y)); | ||||
| 						Z_Buf->setParam(ID::A_SIGNED, false); | ||||
| 						wire_name = "u_mult_Z"; | ||||
| 						auto Z_Wire = module->addWire(new_id(wire_name, __LINE__, ""), z_sz); | ||||
| 						Z_Buf->setPort(ID::A, Z_Wire); | ||||
| 						Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); | ||||
| 						Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); | ||||
| 
 | ||||
| 						CreateBoothUMult(module, x_sz, y_sz, z_sz, | ||||
| 								 A_Wire, // multiplicand
 | ||||
| 								 B_Wire, // multiplier(scanned)
 | ||||
| 								 Z_Wire	 // result
 | ||||
| 						std::string buf_name = "expand_a_buf_"; | ||||
| 						auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); | ||||
| 						buf->setParam(ID::A_WIDTH, x_sz); | ||||
| 						buf->setParam(ID::Y_WIDTH, x_sz_revised); | ||||
| 						buf->setPort(ID::A, SigSpec(A)); | ||||
| 						buf->setParam(ID::A_SIGNED, false); | ||||
| 						buf->setPort(ID::Y, SigSpec(expanded_A)); | ||||
| 
 | ||||
| 						buf_name = "expand_b_buf_"; | ||||
| 						buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); | ||||
| 						buf->setPort(ID::A, SigSpec(B)); | ||||
| 						buf->setParam(ID::A_WIDTH, y_sz); | ||||
| 						buf->setParam(ID::Y_WIDTH, y_sz_revised); | ||||
| 						buf->setParam(ID::A_SIGNED, false); | ||||
| 						buf->setPort(ID::Y, SigSpec(expanded_B)); | ||||
| 
 | ||||
| 						// Make sure output domain is big enough to take
 | ||||
| 						// all combinations.
 | ||||
| 						// Later logic synthesis will kill unused
 | ||||
| 						// portions of the output domain.
 | ||||
| 
 | ||||
| 						unsigned required_op_size = x_sz_revised + y_sz_revised; | ||||
| 
 | ||||
| 						Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); | ||||
| 
 | ||||
| 						CreateBoothUMult(module, x_sz_revised, y_sz_revised, required_op_size, | ||||
| 								 expanded_A, // multiplicand
 | ||||
| 								 expanded_B, // multiplier(scanned)
 | ||||
| 								 expanded_Y  // result
 | ||||
| 						); | ||||
| 
 | ||||
| 						// now connect the expanded_Y with a tap to fill out sig Spec Y
 | ||||
| 
 | ||||
| 						log("Adding reducer on output from %u to %u ", required_op_size, z_sz); | ||||
| 						buf_name = "reducer_buf_"; | ||||
| 						buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); | ||||
| 						buf->setPort(ID::A, expanded_Y); | ||||
| 						buf->setParam(ID::A_WIDTH, required_op_size); | ||||
| 						buf->setParam(ID::Y_WIDTH, z_sz); // The real user width
 | ||||
| 						buf->setParam(ID::A_SIGNED, false); | ||||
| 						// wire in output Y
 | ||||
| 						buf->setPort(ID::Y, SigSpec(Y)); | ||||
| 
 | ||||
| 						module->remove(cell); | ||||
| 						booth_counter++; | ||||
| 						continue; | ||||
|  | @ -344,47 +384,81 @@ struct MultPassWorker { | |||
| 						int y_sz = GetSize(B); | ||||
| 						int z_sz = GetSize(Y); | ||||
| 
 | ||||
| 						// make wire of correct size to feed multiplier
 | ||||
| 						Wire *expanded_A = module->addWire(NEW_ID, x_sz); | ||||
| 						// To simplify the generator size the arguments
 | ||||
| 						// to be the same. Then allow logic synthesis to
 | ||||
| 						// clean things up. Size to biggest
 | ||||
| 
 | ||||
| 						Wire *expanded_B = module->addWire(NEW_ID, y_sz); | ||||
| 						int x_sz_revised = x_sz; | ||||
| 						int y_sz_revised = y_sz; | ||||
| 
 | ||||
| 						if (x_sz != y_sz) { | ||||
| 							if (x_sz < y_sz) { | ||||
| 								if (y_sz % 2 != 0) { | ||||
| 									x_sz_revised = y_sz + 1; | ||||
| 									y_sz_revised = y_sz + 1; | ||||
| 								} else | ||||
| 									x_sz_revised = y_sz; | ||||
| 
 | ||||
| 								log("Resized x to %d ", x_sz_revised); | ||||
| 							} else { | ||||
| 								if (x_sz % 2 != 0) { | ||||
| 									y_sz_revised = x_sz + 1; | ||||
| 									x_sz_revised = x_sz + 1; | ||||
| 								} else | ||||
| 									y_sz_revised = x_sz; | ||||
| 								log("Resized y to %d ", y_sz_revised); | ||||
| 							} | ||||
| 						} else { | ||||
| 							if (x_sz % 2 != 0) { | ||||
| 								y_sz_revised = y_sz + 1; | ||||
| 								x_sz_revised = x_sz + 1; | ||||
| 							} | ||||
| 						} | ||||
| 
 | ||||
| 						log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); | ||||
| 
 | ||||
| 						Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); | ||||
| 						Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); | ||||
| 
 | ||||
| 						std::string buf_name = "expand_a_buf_"; | ||||
| 						auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); | ||||
| 						buf->setParam(ID::A_WIDTH, x_sz); | ||||
| 						buf->setParam(ID::Y_WIDTH, x_sz); | ||||
| 						buf->setParam(ID::Y_WIDTH, x_sz_revised); | ||||
| 						buf->setPort(ID::A, SigSpec(A)); | ||||
| 						buf->setParam(ID::A_SIGNED, is_signed ? true : false); | ||||
| 						buf->setParam(ID::A_SIGNED, true); | ||||
| 						buf->setPort(ID::Y, SigSpec(expanded_A)); | ||||
| 
 | ||||
| 						buf_name = "expand_b_buf_"; | ||||
| 						buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); | ||||
| 						buf->setPort(ID::A, SigSpec(B)); | ||||
| 						buf->setParam(ID::A_WIDTH, y_sz); | ||||
| 						buf->setParam(ID::Y_WIDTH, y_sz); | ||||
| 
 | ||||
| 						buf->setParam(ID::A_SIGNED, is_signed ? true : false); | ||||
| 						buf->setParam(ID::Y_WIDTH, y_sz_revised); | ||||
| 						buf->setParam(ID::A_SIGNED, true); | ||||
| 						buf->setPort(ID::Y, SigSpec(expanded_B)); | ||||
| 
 | ||||
| 						//
 | ||||
| 						// Make a wire to take the expanded output
 | ||||
| 						// wires
 | ||||
| 						//
 | ||||
| 						// Make sure output domain is big enough to take
 | ||||
| 						// all combinations.
 | ||||
| 						// Later logic synthesis will kill unused
 | ||||
| 						// portions of the output domain.
 | ||||
| 
 | ||||
| 						Wire *expanded_Y = module->addWire(NEW_ID, (is_signed == false ? z_sz + 2 : z_sz)); | ||||
| 						CreateBoothSMult(module, x_sz, y_sz, (is_signed == false ? z_sz + 2 : z_sz), | ||||
| 						unsigned required_op_size = x_sz_revised + y_sz_revised; | ||||
| 
 | ||||
| 						Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); | ||||
| 
 | ||||
| 						CreateBoothSMult(module, x_sz_revised, y_sz_revised, required_op_size, | ||||
| 								 expanded_A, // multiplicand
 | ||||
| 								 expanded_B, // multiplier(scanned)
 | ||||
| 								 expanded_Y  // result
 | ||||
| 								 expanded_Y  // result (sized)
 | ||||
| 						); | ||||
| 						// now connect the expanded_Y with a tap to fill out sig Spec Y
 | ||||
| 
 | ||||
| 						log("Adding reducer on output from %u to %u ", required_op_size, z_sz); | ||||
| 						buf_name = "reducer_buf_"; | ||||
| 						buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); | ||||
| 						buf->setPort(ID::A, expanded_Y); | ||||
| 						buf->setParam(ID::A_WIDTH, is_signed == false ? z_sz + 2 : z_sz); | ||||
| 						buf->setParam(ID::Y_WIDTH, z_sz); | ||||
| 						buf->setParam(ID::A_SIGNED, is_signed ? true : false); | ||||
| 						buf->setParam(ID::A_WIDTH, required_op_size); | ||||
| 						buf->setParam(ID::Y_WIDTH, z_sz); // The real user width
 | ||||
| 						buf->setParam(ID::A_SIGNED, true); | ||||
| 						// wire in output Y
 | ||||
| 						buf->setPort(ID::Y, SigSpec(Y)); | ||||
| 
 | ||||
|  | @ -1451,7 +1525,7 @@ struct MultPassWorker { | |||
| 			std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; | ||||
| 			cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1); | ||||
| 		} | ||||
| 		log("    Building cpa array for booth\n"); | ||||
| 		log("    Building cpa array for booth for output size %u\n", z_sz); | ||||
| 		for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { | ||||
| 
 | ||||
| 			// The end case where we pass the last two summands
 | ||||
|  | @ -1525,15 +1599,16 @@ struct MultPassWorker { | |||
| }; | ||||
| 
 | ||||
| struct MultPass : public Pass { | ||||
| 	MultPass() : Pass("multpass") {} | ||||
| 	MultPass() : Pass("multpass", "Map $mul to booth multipliers") {} | ||||
| 	void execute(vector<string> args, RTLIL::Design *design) override | ||||
| 	{ | ||||
| 		(void)args; | ||||
| 		log("Multiplier Pass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); | ||||
| 		log_header(design, "Executing multpass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); | ||||
| 		for (auto mod : design->selected_modules()) | ||||
| 			if (!mod->has_processes_warn()) { | ||||
| 				MultPassWorker worker(mod); | ||||
| 				worker.run(); | ||||
| 				log_header(design, "Created %d booth multipliers.\n", worker.booth_counter); | ||||
| 			} | ||||
| 	} | ||||
| } MultPass; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue