mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-30 19:22:31 +00:00 
			
		
		
		
	add dsp inference
This commit is contained in:
		
							parent
							
								
									7c0dbc8822
								
							
						
					
					
						commit
						9ce53ea3e2
					
				
					 12 changed files with 7189 additions and 7 deletions
				
			
		
							
								
								
									
										1
									
								
								techlibs/quicklogic/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								techlibs/quicklogic/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| /*_pm.h | ||||
|  | @ -1,6 +1,20 @@ | |||
| %_pm.h: passes/pmgen/pmgen.py %.pmg | ||||
| 	$(P) mkdir -p pmgen && $(PYTHON_EXECUTABLE) $< -o $@ -p $(subst _pm.h,,$(notdir $@)) $(filter-out $<,$^) | ||||
| 
 | ||||
| OBJS += techlibs/quicklogic/synth_quicklogic.o | ||||
| OBJS += techlibs/quicklogic/ql-bram-merge.o | ||||
| OBJS += techlibs/quicklogic/ql-bram-types.o | ||||
| OBJS += techlibs/quicklogic/ql_bram_merge.o | ||||
| OBJS += techlibs/quicklogic/ql_bram_types.o | ||||
| OBJS += techlibs/quicklogic/ql_dsp_simd.o | ||||
| OBJS += techlibs/quicklogic/ql_dsp_io_regs.o | ||||
| 
 | ||||
| # --------------------------------------
 | ||||
| 
 | ||||
| OBJS += techlibs/quicklogic/ql_dsp_macc.o | ||||
| GENFILES += techlibs/quicklogic/ql_dsp_macc_pm.h | ||||
| techlibs/quicklogic/ql_dsp_macc.o: techlibs/quicklogic/ql_dsp_macc_pm.h | ||||
| $(eval $(call add_extra_objs,techlibs/quicklogic/ql_dsp_macc_pm.h)) | ||||
| 
 | ||||
| # --------------------------------------
 | ||||
| 
 | ||||
| $(eval $(call add_share_file,share/quicklogic/common,techlibs/quicklogic/common/cells_sim.v)) | ||||
| 
 | ||||
|  | @ -21,4 +35,7 @@ $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf | |||
| $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/brams_sim.v)) | ||||
| $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/bram_types_sim.v)) | ||||
| $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/cells_sim.v)) | ||||
| $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/ffs_map.v)) | ||||
| $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/ffs_map.v)) | ||||
| $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dsp_sim.v)) | ||||
| $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dsp_map.v)) | ||||
| $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dsp_final_map.v)) | ||||
							
								
								
									
										244
									
								
								techlibs/quicklogic/ql_dsp_io_regs.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								techlibs/quicklogic/ql_dsp_io_regs.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,244 @@ | |||
| /*
 | ||||
|  * Copyright 2020-2022 F4PGA Authors | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/sigtools.h" | ||||
| #include "kernel/yosys.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| #define MODE_BITS_REGISTER_INPUTS_ID 92 | ||||
| #define MODE_BITS_OUTPUT_SELECT_START_ID 81 | ||||
| #define MODE_BITS_OUTPUT_SELECT_WIDTH 3 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| struct QlDspIORegs : public Pass { | ||||
| 
 | ||||
| 	const std::vector<std::string> ports2del_mult = {"load_acc", "subtract", "acc_fir", "dly_b"}; | ||||
| 	const std::vector<std::string> ports2del_mult_acc = {"acc_fir", "dly_b"}; | ||||
| 	const std::vector<std::string> ports2del_mult_add = {"dly_b"}; | ||||
| 	const std::vector<std::string> ports2del_extension = {"saturate_enable", "shift_right", "round"}; | ||||
| 
 | ||||
| 	/// Temporary SigBit to SigBit helper map.
 | ||||
| 	SigMap m_SigMap; | ||||
| 
 | ||||
| 	// ..........................................
 | ||||
| 
 | ||||
| 	QlDspIORegs() : Pass("ql_dsp_io_regs", "Changes types of QL_DSP2/QL_DSP3 depending on their configuration.") {} | ||||
| 
 | ||||
| 	void help() override | ||||
| 	{ | ||||
| 		log("\n"); | ||||
| 		log("    ql_dsp_io_regs [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Looks for QL_DSP2/QL_DSP3 cells and changes their types depending\n"); | ||||
| 		log("on their configuration.\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> a_Args, RTLIL::Design *a_Design) override | ||||
| 	{ | ||||
| 		log_header(a_Design, "Executing QL_DSP_IO_REGS pass.\n"); | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < a_Args.size(); argidx++) { | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(a_Args, argidx, a_Design); | ||||
| 
 | ||||
| 		for (auto module : a_Design->selected_modules()) { | ||||
| 			ql_dsp_io_regs_pass(module); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Returns a pair of mask and value describing constant bit connections of
 | ||||
| 	// a SigSpec
 | ||||
| 	std::pair<uint32_t, uint32_t> get_constant_mask_value(const RTLIL::SigSpec *sigspec) | ||||
| 	{ | ||||
| 		uint32_t mask = 0L; | ||||
| 		uint32_t value = 0L; | ||||
| 
 | ||||
| 		auto sigbits = sigspec->bits(); | ||||
| 		for (ssize_t i = (sigbits.size() - 1); i >= 0; --i) { | ||||
| 			auto other = m_SigMap(sigbits[i]); | ||||
| 
 | ||||
| 			mask <<= 1; | ||||
| 			value <<= 1; | ||||
| 
 | ||||
| 			// A known constant
 | ||||
| 			if (!other.is_wire() && other.data != RTLIL::Sx) { | ||||
| 				mask |= 0x1; | ||||
| 				value |= (other.data == RTLIL::S1); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return std::make_pair(mask, value); | ||||
| 	} | ||||
| 
 | ||||
| 	void ql_dsp_io_regs_pass(RTLIL::Module *module) | ||||
| 	{ | ||||
| 		// Setup the SigMap
 | ||||
| 		m_SigMap.clear(); | ||||
| 		m_SigMap.set(module); | ||||
| 
 | ||||
| 		for (auto cell : module->cells_) { | ||||
| 			std::string cell_type = cell.second->type.str(); | ||||
| 			if (cell_type == RTLIL::escape_id("QL_DSP2") || cell_type == RTLIL::escape_id("QL_DSP3")) { | ||||
| 				auto dsp = cell.second; | ||||
| 
 | ||||
| 				// If the cell does not have the "is_inferred" attribute set
 | ||||
| 				// then don't touch it.
 | ||||
| 				if (!dsp->has_attribute(RTLIL::escape_id("is_inferred")) || dsp->get_bool_attribute(RTLIL::escape_id("is_inferred")) == false) { | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 				bool del_clk = true; | ||||
| 				bool use_dsp_cfg_params = (cell_type == RTLIL::escape_id("QL_DSP3")); | ||||
| 
 | ||||
| 				int reg_in_i; | ||||
| 				int out_sel_i; | ||||
| 
 | ||||
| 				// Get DSP configuration
 | ||||
| 				if (use_dsp_cfg_params) { | ||||
| 					// Read MODE_BITS at correct indexes
 | ||||
| 					auto mode_bits = &dsp->getParam(RTLIL::escape_id("MODE_BITS")); | ||||
| 					RTLIL::Const register_inputs; | ||||
| 					register_inputs = mode_bits->bits.at(MODE_BITS_REGISTER_INPUTS_ID); | ||||
| 					reg_in_i = register_inputs.as_int(); | ||||
| 
 | ||||
| 					RTLIL::Const output_select; | ||||
| 					output_select = mode_bits->extract(MODE_BITS_OUTPUT_SELECT_START_ID, MODE_BITS_OUTPUT_SELECT_WIDTH); | ||||
| 					out_sel_i = output_select.as_int(); | ||||
| 				} else { | ||||
| 					// Read dedicated configuration ports
 | ||||
| 					const RTLIL::SigSpec *register_inputs; | ||||
| 					register_inputs = &dsp->getPort(RTLIL::escape_id("register_inputs")); | ||||
| 					if (!register_inputs) | ||||
| 						log_error("register_inputs port not found!"); | ||||
| 					auto reg_in_c = register_inputs->as_const(); | ||||
| 					reg_in_i = reg_in_c.as_int(); | ||||
| 
 | ||||
| 					const RTLIL::SigSpec *output_select; | ||||
| 					output_select = &dsp->getPort(RTLIL::escape_id("output_select")); | ||||
| 					if (!output_select) | ||||
| 						log_error("output_select port not found!"); | ||||
| 					auto out_sel_c = output_select->as_const(); | ||||
| 					out_sel_i = out_sel_c.as_int(); | ||||
| 				} | ||||
| 
 | ||||
| 				// Get the feedback port
 | ||||
| 				const RTLIL::SigSpec *feedback; | ||||
| 				feedback = &dsp->getPort(RTLIL::escape_id("feedback")); | ||||
| 				if (!feedback) | ||||
| 					log_error("feedback port not found!"); | ||||
| 
 | ||||
| 				// Check if feedback is or can be set to 0 which implies MACC
 | ||||
| 				auto feedback_con = get_constant_mask_value(feedback); | ||||
| 				bool have_macc = (feedback_con.second == 0x0); | ||||
| 				// log("mask=0x%08X value=0x%08X\n", consts.first, consts.second);
 | ||||
| 				// log_error("=== END HERE ===\n");
 | ||||
| 
 | ||||
| 				// Build new type name
 | ||||
| 				std::string new_type = cell_type; | ||||
| 				new_type += "_MULT"; | ||||
| 
 | ||||
| 				if (have_macc) { | ||||
| 					switch (out_sel_i) { | ||||
| 					case 1: | ||||
| 					case 2: | ||||
| 					case 3: | ||||
| 					case 5: | ||||
| 					case 7: | ||||
| 						del_clk = false; | ||||
| 						new_type += "ACC"; | ||||
| 						break; | ||||
| 					default: | ||||
| 						break; | ||||
| 					} | ||||
| 				} else { | ||||
| 					switch (out_sel_i) { | ||||
| 					case 1: | ||||
| 					case 2: | ||||
| 					case 3: | ||||
| 					case 5: | ||||
| 					case 7: | ||||
| 						new_type += "ADD"; | ||||
| 						break; | ||||
| 					default: | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				if (reg_in_i) { | ||||
| 					del_clk = false; | ||||
| 					new_type += "_REGIN"; | ||||
| 				} | ||||
| 
 | ||||
| 				if (out_sel_i > 3) { | ||||
| 					del_clk = false; | ||||
| 					new_type += "_REGOUT"; | ||||
| 				} | ||||
| 
 | ||||
| 				// Set new type name
 | ||||
| 				dsp->type = RTLIL::IdString(new_type); | ||||
| 
 | ||||
| 				std::vector<std::string> ports2del; | ||||
| 
 | ||||
| 				if (del_clk) | ||||
| 					ports2del.push_back("clk"); | ||||
| 
 | ||||
| 				switch (out_sel_i) { | ||||
| 				case 0: | ||||
| 				case 4: | ||||
| 				case 6: | ||||
| 					ports2del.insert(ports2del.end(), ports2del_mult.begin(), ports2del_mult.end()); | ||||
| 					// Mark for deleton additional configuration ports
 | ||||
| 					if (!use_dsp_cfg_params) { | ||||
| 						ports2del.insert(ports2del.end(), ports2del_extension.begin(), ports2del_extension.end()); | ||||
| 					} | ||||
| 					break; | ||||
| 				case 1: | ||||
| 				case 2: | ||||
| 				case 3: | ||||
| 				case 5: | ||||
| 				case 7: | ||||
| 					if (have_macc) { | ||||
| 						ports2del.insert(ports2del.end(), ports2del_mult_acc.begin(), ports2del_mult_acc.end()); | ||||
| 					} else { | ||||
| 						ports2del.insert(ports2del.end(), ports2del_mult_add.begin(), ports2del_mult_add.end()); | ||||
| 					} | ||||
| 					break; | ||||
| 				} | ||||
| 
 | ||||
| 				for (auto portname : ports2del) { | ||||
| 					const RTLIL::SigSpec *port = &dsp->getPort(RTLIL::escape_id(portname)); | ||||
| 					if (!port) | ||||
| 						log_error("%s port not found!", portname.c_str()); | ||||
| 					dsp->connections_.erase(RTLIL::escape_id(portname)); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Clear the sigmap
 | ||||
| 		m_SigMap.clear(); | ||||
| 	} | ||||
| 
 | ||||
| } QlDspIORegs; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
							
								
								
									
										307
									
								
								techlibs/quicklogic/ql_dsp_macc.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										307
									
								
								techlibs/quicklogic/ql_dsp_macc.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,307 @@ | |||
| /*
 | ||||
|  * Copyright 2020-2022 F4PGA Authors | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/sigtools.h" | ||||
| #include "kernel/yosys.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| #include "ql_dsp_macc_pm.h" | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| bool use_dsp_cfg_params; | ||||
| 
 | ||||
| static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) | ||||
| { | ||||
| 	auto &st = pm.st_ql_dsp_macc; | ||||
| 
 | ||||
| 	// Reject if multiplier drives anything else than either $add or $add and
 | ||||
| 	// $mux
 | ||||
| 	if (st.mux == nullptr && st.mul_nusers > 2) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	// Determine whether the output is taken from before or after the ff
 | ||||
| 	bool out_ff; | ||||
| 	if (st.ff_d_nusers == 2 && st.ff_q_nusers == 3) { | ||||
| 		out_ff = true; | ||||
| 	} else if (st.ff_d_nusers == 3 && st.ff_q_nusers == 2) { | ||||
| 		out_ff = false; | ||||
| 	} else { | ||||
| 		// Illegal, cannot take the two outputs simulataneously
 | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	// No mux, the adder can driver either the ff or the ff + output
 | ||||
| 	if (st.mux == nullptr) { | ||||
| 		if (out_ff && st.add_nusers != 2) { | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!out_ff && st.add_nusers != 3) { | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 	// Mux present, the adder cannot drive anything else
 | ||||
| 	else { | ||||
| 		if (st.add_nusers != 2) { | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Mux can driver either the ff or the ff + output
 | ||||
| 	if (st.mux != nullptr) { | ||||
| 		if (out_ff && st.mux_nusers != 2) { | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!out_ff && st.mux_nusers != 3) { | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Accept only posedge clocked FFs
 | ||||
| 	if (st.ff->getParam(ID(CLK_POLARITY)).as_int() != 1) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	// Get port widths
 | ||||
| 	size_t a_width = GetSize(st.mul->getPort(ID(A))); | ||||
| 	size_t b_width = GetSize(st.mul->getPort(ID(B))); | ||||
| 	size_t z_width = GetSize(st.ff->getPort(ID(Q))); | ||||
| 
 | ||||
| 	size_t min_width = std::min(a_width, b_width); | ||||
| 	size_t max_width = std::max(a_width, b_width); | ||||
| 
 | ||||
| 	// Signed / unsigned
 | ||||
| 	bool a_signed = st.mul->getParam(ID(A_SIGNED)).as_bool(); | ||||
| 	bool b_signed = st.mul->getParam(ID(B_SIGNED)).as_bool(); | ||||
| 
 | ||||
| 	// Determine DSP type or discard if too narrow / wide
 | ||||
| 	RTLIL::IdString type; | ||||
| 	size_t tgt_a_width; | ||||
| 	size_t tgt_b_width; | ||||
| 	size_t tgt_z_width; | ||||
| 
 | ||||
| 	string cell_base_name = "dsp_t1"; | ||||
| 	string cell_size_name = ""; | ||||
| 	string cell_cfg_name = ""; | ||||
| 	string cell_full_name = ""; | ||||
| 
 | ||||
| 	if (min_width <= 2 && max_width <= 2 && z_width <= 4) { | ||||
| 		// Too narrow
 | ||||
| 		return; | ||||
| 	} else if (min_width <= 9 && max_width <= 10 && z_width <= 19) { | ||||
| 		cell_size_name = "_10x9x32"; | ||||
| 		tgt_a_width = 10; | ||||
| 		tgt_b_width = 9; | ||||
| 		tgt_z_width = 19; | ||||
| 	} else if (min_width <= 18 && max_width <= 20 && z_width <= 38) { | ||||
| 		cell_size_name = "_20x18x64"; | ||||
| 		tgt_a_width = 20; | ||||
| 		tgt_b_width = 18; | ||||
| 		tgt_z_width = 38; | ||||
| 	} else { | ||||
| 		// Too wide
 | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (use_dsp_cfg_params) | ||||
| 		cell_cfg_name = "_cfg_params"; | ||||
| 	else | ||||
| 		cell_cfg_name = "_cfg_ports"; | ||||
| 
 | ||||
| 	cell_full_name = cell_base_name + cell_size_name + cell_cfg_name; | ||||
| 
 | ||||
| 	type = RTLIL::escape_id(cell_full_name); | ||||
| 	log("Inferring MACC %zux%zu->%zu as %s from:\n", a_width, b_width, z_width, RTLIL::unescape_id(type).c_str()); | ||||
| 
 | ||||
| 	for (auto cell : {st.mul, st.add, st.mux, st.ff}) { | ||||
| 		if (cell != nullptr) { | ||||
| 			log(" %s (%s)\n", RTLIL::unescape_id(cell->name).c_str(), RTLIL::unescape_id(cell->type).c_str()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Build the DSP cell name
 | ||||
| 	std::string name; | ||||
| 	name += RTLIL::unescape_id(st.mul->name) + "_"; | ||||
| 	name += RTLIL::unescape_id(st.add->name) + "_"; | ||||
| 	if (st.mux != nullptr) { | ||||
| 		name += RTLIL::unescape_id(st.mux->name) + "_"; | ||||
| 	} | ||||
| 	name += RTLIL::unescape_id(st.ff->name); | ||||
| 
 | ||||
| 	// Add the DSP cell
 | ||||
| 	RTLIL::Cell *cell = pm.module->addCell(RTLIL::escape_id(name), type); | ||||
| 
 | ||||
| 	// Set attributes
 | ||||
| 	cell->set_bool_attribute(RTLIL::escape_id("is_inferred"), true); | ||||
| 
 | ||||
| 	// Get input/output data signals
 | ||||
| 	RTLIL::SigSpec sig_a; | ||||
| 	RTLIL::SigSpec sig_b; | ||||
| 	RTLIL::SigSpec sig_z; | ||||
| 
 | ||||
| 	if (a_width >= b_width) { | ||||
| 		sig_a = st.mul->getPort(ID(A)); | ||||
| 		sig_b = st.mul->getPort(ID(B)); | ||||
| 	} else { | ||||
| 		sig_a = st.mul->getPort(ID(B)); | ||||
| 		sig_b = st.mul->getPort(ID(A)); | ||||
| 	} | ||||
| 
 | ||||
| 	sig_z = out_ff ? st.ff->getPort(ID(Q)) : st.ff->getPort(ID(D)); | ||||
| 
 | ||||
| 	// Connect input data ports, sign extend / pad with zeros
 | ||||
| 	sig_a.extend_u0(tgt_a_width, a_signed); | ||||
| 	sig_b.extend_u0(tgt_b_width, b_signed); | ||||
| 	cell->setPort(RTLIL::escape_id("a_i"), sig_a); | ||||
| 	cell->setPort(RTLIL::escape_id("b_i"), sig_b); | ||||
| 
 | ||||
| 	// Connect output data port, pad if needed
 | ||||
| 	if ((size_t)GetSize(sig_z) < tgt_z_width) { | ||||
| 		auto *wire = pm.module->addWire(NEW_ID, tgt_z_width - GetSize(sig_z)); | ||||
| 		sig_z.append(wire); | ||||
| 	} | ||||
| 	cell->setPort(RTLIL::escape_id("z_o"), sig_z); | ||||
| 
 | ||||
| 	// Connect clock, reset and enable
 | ||||
| 	cell->setPort(RTLIL::escape_id("clock_i"), st.ff->getPort(ID(CLK))); | ||||
| 
 | ||||
| 	RTLIL::SigSpec rst; | ||||
| 	RTLIL::SigSpec ena; | ||||
| 
 | ||||
| 	if (st.ff->hasPort(ID(ARST))) { | ||||
| 		if (st.ff->getParam(ID(ARST_POLARITY)).as_int() != 1) { | ||||
| 			rst = pm.module->Not(NEW_ID, st.ff->getPort(ID(ARST))); | ||||
| 		} else { | ||||
| 			rst = st.ff->getPort(ID(ARST)); | ||||
| 		} | ||||
| 	} else { | ||||
| 		rst = RTLIL::SigSpec(RTLIL::S0); | ||||
| 	} | ||||
| 
 | ||||
| 	if (st.ff->hasPort(ID(EN))) { | ||||
| 		if (st.ff->getParam(ID(EN_POLARITY)).as_int() != 1) { | ||||
| 			ena = pm.module->Not(NEW_ID, st.ff->getPort(ID(EN))); | ||||
| 		} else { | ||||
| 			ena = st.ff->getPort(ID(EN)); | ||||
| 		} | ||||
| 	} else { | ||||
| 		ena = RTLIL::SigSpec(RTLIL::S1); | ||||
| 	} | ||||
| 
 | ||||
| 	cell->setPort(RTLIL::escape_id("reset_i"), rst); | ||||
| 	cell->setPort(RTLIL::escape_id("load_acc_i"), ena); | ||||
| 
 | ||||
| 	// Insert feedback_i control logic used for clearing / loading the accumulator
 | ||||
| 	if (st.mux != nullptr) { | ||||
| 		RTLIL::SigSpec sig_s = st.mux->getPort(ID(S)); | ||||
| 
 | ||||
| 		// Depending on the mux port ordering insert inverter if needed
 | ||||
| 		log_assert(st.mux_ab == ID(A) || st.mux_ab == ID(B)); | ||||
| 		if (st.mux_ab == ID(A)) { | ||||
| 			sig_s = pm.module->Not(NEW_ID, sig_s); | ||||
| 		} | ||||
| 
 | ||||
| 		// Assemble the full control signal for the feedback_i port
 | ||||
| 		RTLIL::SigSpec sig_f; | ||||
| 		sig_f.append(sig_s); | ||||
| 		sig_f.append(RTLIL::S0); | ||||
| 		sig_f.append(RTLIL::S0); | ||||
| 		cell->setPort(RTLIL::escape_id("feedback_i"), sig_f); | ||||
| 	} | ||||
| 	// No acc clear/load
 | ||||
| 	else { | ||||
| 		cell->setPort(RTLIL::escape_id("feedback_i"), RTLIL::SigSpec(RTLIL::S0, 3)); | ||||
| 	} | ||||
| 
 | ||||
| 	// Connect control ports
 | ||||
| 	cell->setPort(RTLIL::escape_id("unsigned_a_i"), RTLIL::SigSpec(a_signed ? RTLIL::S0 : RTLIL::S1)); | ||||
| 	cell->setPort(RTLIL::escape_id("unsigned_b_i"), RTLIL::SigSpec(b_signed ? RTLIL::S0 : RTLIL::S1)); | ||||
| 
 | ||||
| 	// Connect config bits
 | ||||
| 	if (use_dsp_cfg_params) { | ||||
| 		cell->setParam(RTLIL::escape_id("SATURATE_ENABLE"), RTLIL::Const(RTLIL::S0)); | ||||
| 		cell->setParam(RTLIL::escape_id("SHIFT_RIGHT"), RTLIL::Const(RTLIL::S0, 6)); | ||||
| 		cell->setParam(RTLIL::escape_id("ROUND"), RTLIL::Const(RTLIL::S0)); | ||||
| 		cell->setParam(RTLIL::escape_id("REGISTER_INPUTS"), RTLIL::Const(RTLIL::S0)); | ||||
| 		// 3 - output post acc; 1 - output pre acc
 | ||||
| 		cell->setParam(RTLIL::escape_id("OUTPUT_SELECT"), out_ff ? RTLIL::Const(1, 3) : RTLIL::Const(3, 3)); | ||||
| 	} else { | ||||
| 		cell->setPort(RTLIL::escape_id("saturate_enable_i"), RTLIL::SigSpec(RTLIL::S0)); | ||||
| 		cell->setPort(RTLIL::escape_id("shift_right_i"), RTLIL::SigSpec(RTLIL::S0, 6)); | ||||
| 		cell->setPort(RTLIL::escape_id("round_i"), RTLIL::SigSpec(RTLIL::S0)); | ||||
| 		cell->setPort(RTLIL::escape_id("register_inputs_i"), RTLIL::SigSpec(RTLIL::S0)); | ||||
| 		// 3 - output post acc; 1 - output pre acc
 | ||||
| 		cell->setPort(RTLIL::escape_id("output_select_i"), out_ff ? RTLIL::Const(1, 3) : RTLIL::Const(3, 3)); | ||||
| 	} | ||||
| 
 | ||||
| 	bool subtract = (st.add->type == RTLIL::escape_id("$sub")); | ||||
| 	cell->setPort(RTLIL::escape_id("subtract_i"), RTLIL::SigSpec(subtract ? RTLIL::S1 : RTLIL::S0)); | ||||
| 
 | ||||
| 	// Mark the cells for removal
 | ||||
| 	pm.autoremove(st.mul); | ||||
| 	pm.autoremove(st.add); | ||||
| 	if (st.mux != nullptr) { | ||||
| 		pm.autoremove(st.mux); | ||||
| 	} | ||||
| 	pm.autoremove(st.ff); | ||||
| } | ||||
| 
 | ||||
| struct QlDspMacc : public Pass { | ||||
| 
 | ||||
| 	QlDspMacc() : Pass("ql_dsp_macc", "Does something") {} | ||||
| 
 | ||||
| 	void help() override | ||||
| 	{ | ||||
| 		log("\n"); | ||||
| 		log("    ql_dsp_macc [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -use_dsp_cfg_params\n"); | ||||
| 		log("        By default use DSP blocks with configuration bits available at module ports.\n"); | ||||
| 		log("        Specifying this forces usage of DSP block with configuration bits available as module parameters\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	void clear_flags() override { use_dsp_cfg_params = false; } | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> a_Args, RTLIL::Design *a_Design) override | ||||
| 	{ | ||||
| 		log_header(a_Design, "Executing QL_DSP_MACC pass.\n"); | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < a_Args.size(); argidx++) { | ||||
| 			if (a_Args[argidx] == "-use_dsp_cfg_params") { | ||||
| 				use_dsp_cfg_params = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(a_Args, argidx, a_Design); | ||||
| 
 | ||||
| 		for (auto module : a_Design->selected_modules()) { | ||||
| 			ql_dsp_macc_pm(module, module->selected_cells()).run_ql_dsp_macc(create_ql_macc_dsp); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } QlDspMacc; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
							
								
								
									
										50
									
								
								techlibs/quicklogic/ql_dsp_macc.pmg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								techlibs/quicklogic/ql_dsp_macc.pmg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| pattern ql_dsp_macc | ||||
| 
 | ||||
| state <IdString> add_ba | ||||
| state <IdString> mux_ab | ||||
| 
 | ||||
| state <int> mul_nusers | ||||
| state <int> add_nusers | ||||
| state <int> mux_nusers | ||||
| state <int> ff_d_nusers | ||||
| state <int> ff_q_nusers | ||||
| 
 | ||||
| match mul | ||||
|     select mul->type.in($mul) | ||||
|     select nusers(port(mul, \Y)) <= 3 | ||||
|     set mul_nusers nusers(port(mul, \Y)) | ||||
| endmatch | ||||
| 
 | ||||
| match add | ||||
|     select add->type.in($add, $sub) | ||||
|     choice <IdString> AB {\A, \B} | ||||
|     define <IdString> BA (AB == \A ? \B : \A) | ||||
|     index <SigSpec> port(add, AB) === port(mul, \Y) | ||||
|     select nusers(port(add, \Y)) <= 3 | ||||
|     set add_nusers nusers(port(add, \Y)) | ||||
|     set add_ba BA | ||||
| endmatch | ||||
| 
 | ||||
| match mux | ||||
|     select mux->type.in($mux) | ||||
|     choice <IdString> AB {\A, \B} | ||||
|     define <IdString> BA (AB == \A ? \B : \A) | ||||
|     index <SigSpec> port(mux, AB) === port(mul, \Y) | ||||
|     index <SigSpec> port(mux, BA) === port(add, \Y) | ||||
|     select nusers(port(mux, \Y)) <= 3 | ||||
|     set mux_nusers nusers(port(mux, \Y)) | ||||
|     set mux_ab AB | ||||
|     optional | ||||
| endmatch | ||||
| 
 | ||||
| match ff | ||||
|     select ff->type.in($dff, $adff, $dffe, $adffe) | ||||
|     index <SigSpec> port(ff, \D) === (mux == nullptr ? port(add, \Y) : port(mux, \Y)) | ||||
|     index <SigSpec> port(ff, \Q) === port(add, add_ba) | ||||
|     set ff_d_nusers nusers(port(ff, \D)) | ||||
|     set ff_q_nusers nusers(port(ff, \Q)) | ||||
| endmatch | ||||
| 
 | ||||
| code | ||||
|     accept; | ||||
| endcode | ||||
							
								
								
									
										359
									
								
								techlibs/quicklogic/ql_dsp_simd.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								techlibs/quicklogic/ql_dsp_simd.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,359 @@ | |||
| /*
 | ||||
|  * Copyright 2020-2022 F4PGA Authors | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/log.h" | ||||
| #include "kernel/register.h" | ||||
| #include "kernel/rtlil.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| #define MODE_BITS_BASE_SIZE 80 | ||||
| #define MODE_BITS_EXTENSION_SIZE 13 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| struct QlDspSimdPass : public Pass { | ||||
| 
 | ||||
| 	QlDspSimdPass() : Pass("ql_dsp_simd", "Infers QuickLogic k6n10f DSP pairs that can operate in SIMD mode") {} | ||||
| 
 | ||||
| 	void help() override | ||||
| 	{ | ||||
| 		log("\n"); | ||||
| 		log("    ql_dsp_simd [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("    This pass identifies k6n10f DSP cells with identical configuration\n"); | ||||
| 		log("    and packs pairs of them together into other DSP cells that can\n"); | ||||
| 		log("    perform SIMD operation.\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	// ..........................................
 | ||||
| 
 | ||||
| 	/// Describes DSP config unique to a whole DSP cell
 | ||||
| 	struct DspConfig { | ||||
| 
 | ||||
| 		// Port connections
 | ||||
| 		dict<RTLIL::IdString, RTLIL::SigSpec> connections; | ||||
| 
 | ||||
| 		// Whether DSPs pass configuration bits through ports of parameters
 | ||||
| 		bool use_cfg_params; | ||||
| 
 | ||||
| 		// TODO: Possibly include parameters here. For now we have just
 | ||||
| 		// connections.
 | ||||
| 
 | ||||
| 		DspConfig() = default; | ||||
| 
 | ||||
| 		DspConfig(const DspConfig &ref) = default; | ||||
| 		DspConfig(DspConfig &&ref) = default; | ||||
| 
 | ||||
| 		unsigned int hash() const { return connections.hash(); } | ||||
| 
 | ||||
| 		bool operator==(const DspConfig &ref) const { return connections == ref.connections && use_cfg_params == ref.use_cfg_params; } | ||||
| 	}; | ||||
| 
 | ||||
| 	// ..........................................
 | ||||
| 
 | ||||
| 	// DSP control and config ports to consider and how to map them to ports
 | ||||
| 	// of the target DSP cell
 | ||||
| 	const std::vector<std::pair<std::string, std::string>> m_DspCfgPorts = {std::make_pair("clock_i", "clk"), | ||||
| 																			std::make_pair("reset_i", "reset"), | ||||
| 
 | ||||
| 																			std::make_pair("feedback_i", "feedback"), | ||||
| 																			std::make_pair("load_acc_i", "load_acc"), | ||||
| 																			std::make_pair("unsigned_a_i", "unsigned_a"), | ||||
| 																			std::make_pair("unsigned_b_i", "unsigned_b"), | ||||
| 
 | ||||
| 																			std::make_pair("subtract_i", "subtract")}; | ||||
| 	// For QL_DSP2 expand with configuration ports
 | ||||
| 	const std::vector<std::pair<std::string, std::string>> m_DspCfgPorts_expand = { | ||||
| 	  std::make_pair("output_select_i", "output_select"), std::make_pair("saturate_enable_i", "saturate_enable"), | ||||
| 	  std::make_pair("shift_right_i", "shift_right"), std::make_pair("round_i", "round"), std::make_pair("register_inputs_i", "register_inputs")}; | ||||
| 
 | ||||
| 	// For QL_DSP3 use parameters instead
 | ||||
| 	const std::vector<std::string> m_DspParams2Mode = {"OUTPUT_SELECT", "SATURATE_ENABLE", "SHIFT_RIGHT", "ROUND", "REGISTER_INPUTS"}; | ||||
| 
 | ||||
| 	// DSP data ports and how to map them to ports of the target DSP cell
 | ||||
| 	const std::vector<std::pair<std::string, std::string>> m_DspDataPorts = { | ||||
| 	  std::make_pair("a_i", "a"), std::make_pair("b_i", "b"),         std::make_pair("acc_fir_i", "acc_fir"), | ||||
| 	  std::make_pair("z_o", "z"), std::make_pair("dly_b_o", "dly_b"), | ||||
| 	}; | ||||
| 
 | ||||
| 	// DSP parameters
 | ||||
| 	const std::vector<std::string> m_DspParams = {"COEFF_3", "COEFF_2", "COEFF_1", "COEFF_0"}; | ||||
| 
 | ||||
| 	// Source DSP cell type (SISD)
 | ||||
| 	const std::string m_SisdDspType = "dsp_t1_10x9x32"; | ||||
| 	// Suffix for DSP cell with configuration parameters
 | ||||
| 	const std::string m_SisdDspType_cfg_params_suffix = "_cfg_params"; | ||||
| 
 | ||||
| 	// Target DSP cell types for the SIMD mode
 | ||||
| 	const std::string m_SimdDspType_cfg_ports = "QL_DSP2"; | ||||
| 	const std::string m_SimdDspType_cfg_params = "QL_DSP3"; | ||||
| 
 | ||||
| 	/// Temporary SigBit to SigBit helper map.
 | ||||
| 	SigMap m_SigMap; | ||||
| 
 | ||||
| 	// ..........................................
 | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> a_Args, RTLIL::Design *a_Design) override | ||||
| 	{ | ||||
| 		log_header(a_Design, "Executing QL_DSP_SIMD pass.\n"); | ||||
| 
 | ||||
| 		// Parse args
 | ||||
| 		extra_args(a_Args, 1, a_Design); | ||||
| 
 | ||||
| 		// Process modules
 | ||||
| 		for (auto module : a_Design->selected_modules()) { | ||||
| 
 | ||||
| 			// Setup the SigMap
 | ||||
| 			m_SigMap.clear(); | ||||
| 			m_SigMap.set(module); | ||||
| 
 | ||||
| 			// Assemble DSP cell groups
 | ||||
| 			dict<DspConfig, std::vector<RTLIL::Cell *>> groups; | ||||
| 			for (auto cell : module->selected_cells()) { | ||||
| 
 | ||||
| 				// Check if this is a DSP cell we are looking for (type starts with m_SisdDspType)
 | ||||
| 				if (strncmp(cell->type.c_str(), RTLIL::escape_id(m_SisdDspType).c_str(), RTLIL::escape_id(m_SisdDspType).size()) != 0) { | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 				// Skip if it has the (* keep *) attribute set
 | ||||
| 				if (cell->has_keep_attr()) { | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 				// Add to a group
 | ||||
| 				const auto key = getDspConfig(cell); | ||||
| 				groups[key].push_back(cell); | ||||
| 			} | ||||
| 
 | ||||
| 			std::vector<const RTLIL::Cell *> cellsToRemove; | ||||
| 
 | ||||
| 			// Map cell pairs to the target DSP SIMD cell
 | ||||
| 			for (const auto &it : groups) { | ||||
| 				const auto &group = it.second; | ||||
| 				const auto &config = it.first; | ||||
| 
 | ||||
| 				bool use_cfg_params = config.use_cfg_params; | ||||
| 				// Ensure an even number
 | ||||
| 				size_t count = group.size(); | ||||
| 				if (count & 1) | ||||
| 					count--; | ||||
| 
 | ||||
| 				// Map SIMD pairs
 | ||||
| 				for (size_t i = 0; i < count; i += 2) { | ||||
| 					const RTLIL::Cell *dsp_a = group[i]; | ||||
| 					const RTLIL::Cell *dsp_b = group[i + 1]; | ||||
| 
 | ||||
| 					std::string name = stringf("simd%ld", i / 2); | ||||
| 					std::string SimdDspType; | ||||
| 
 | ||||
| 					if (use_cfg_params) | ||||
| 						SimdDspType = m_SimdDspType_cfg_params; | ||||
| 					else | ||||
| 						SimdDspType = m_SimdDspType_cfg_ports; | ||||
| 
 | ||||
| 					log(" SIMD: %s (%s) + %s (%s) => %s (%s)\n", RTLIL::unescape_id(dsp_a->name).c_str(), RTLIL::unescape_id(dsp_a->type).c_str(), | ||||
| 						RTLIL::unescape_id(dsp_b->name).c_str(), RTLIL::unescape_id(dsp_b->type).c_str(), RTLIL::unescape_id(name).c_str(), | ||||
| 						SimdDspType.c_str()); | ||||
| 
 | ||||
| 					// Create the new cell
 | ||||
| 					RTLIL::Cell *simd = module->addCell(RTLIL::escape_id(name), RTLIL::escape_id(SimdDspType)); | ||||
| 
 | ||||
| 					// Check if the target cell is known (important to know
 | ||||
| 					// its port widths)
 | ||||
| 					if (!simd->known()) { | ||||
| 						log_error(" The target cell type '%s' is not known!", SimdDspType.c_str()); | ||||
| 					} | ||||
| 
 | ||||
| 					std::vector<std::pair<std::string, std::string>> DspCfgPorts = m_DspCfgPorts; | ||||
| 					if (!use_cfg_params) | ||||
| 						DspCfgPorts.insert(DspCfgPorts.end(), m_DspCfgPorts_expand.begin(), m_DspCfgPorts_expand.end()); | ||||
| 
 | ||||
| 					// Connect common ports
 | ||||
| 					for (const auto &it : DspCfgPorts) { | ||||
| 						auto sport = RTLIL::escape_id(it.first); | ||||
| 						auto dport = RTLIL::escape_id(it.second); | ||||
| 
 | ||||
| 						simd->setPort(dport, config.connections.at(sport)); | ||||
| 					} | ||||
| 
 | ||||
| 					// Connect data ports
 | ||||
| 					for (const auto &it : m_DspDataPorts) { | ||||
| 						auto sport = RTLIL::escape_id(it.first); | ||||
| 						auto dport = RTLIL::escape_id(it.second); | ||||
| 
 | ||||
| 						size_t width; | ||||
| 						bool isOutput; | ||||
| 
 | ||||
| 						std::tie(width, isOutput) = getPortInfo(simd, dport); | ||||
| 
 | ||||
| 						auto getConnection = [&](const RTLIL::Cell *cell) { | ||||
| 							RTLIL::SigSpec sigspec; | ||||
| 							if (cell->hasPort(sport)) { | ||||
| 								const auto &sig = cell->getPort(sport); | ||||
| 								sigspec.append(sig); | ||||
| 							} | ||||
| 							if (sigspec.bits().size() < width / 2) { | ||||
| 								if (isOutput) { | ||||
| 									for (size_t i = 0; i < width / 2 - sigspec.bits().size(); ++i) { | ||||
| 										sigspec.append(RTLIL::SigSpec()); | ||||
| 									} | ||||
| 								} else { | ||||
| 									sigspec.append(RTLIL::SigSpec(RTLIL::Sx, width / 2 - sigspec.bits().size())); | ||||
| 								} | ||||
| 							} | ||||
| 							return sigspec; | ||||
| 						}; | ||||
| 
 | ||||
| 						RTLIL::SigSpec sigspec; | ||||
| 						sigspec.append(getConnection(dsp_a)); | ||||
| 						sigspec.append(getConnection(dsp_b)); | ||||
| 						simd->setPort(dport, sigspec); | ||||
| 					} | ||||
| 
 | ||||
| 					// Concatenate FIR coefficient parameters into the single
 | ||||
| 					// MODE_BITS parameter
 | ||||
| 					std::vector<RTLIL::State> mode_bits; | ||||
| 					for (const auto &it : m_DspParams) { | ||||
| 						auto val_a = dsp_a->getParam(RTLIL::escape_id(it)); | ||||
| 						auto val_b = dsp_b->getParam(RTLIL::escape_id(it)); | ||||
| 
 | ||||
| 						mode_bits.insert(mode_bits.end(), val_a.begin(), val_a.end()); | ||||
| 						mode_bits.insert(mode_bits.end(), val_b.begin(), val_b.end()); | ||||
| 					} | ||||
| 					long unsigned int mode_bits_size = MODE_BITS_BASE_SIZE; | ||||
| 					if (use_cfg_params) { | ||||
| 						// Add additional config parameters if necessary
 | ||||
| 						mode_bits.push_back(RTLIL::S1); // MODE_BITS[80] == F_MODE : Enable fractured mode
 | ||||
| 						for (const auto &it : m_DspParams2Mode) { | ||||
| 							log_assert(dsp_a->getParam(RTLIL::escape_id(it)) == dsp_b->getParam(RTLIL::escape_id(it))); | ||||
| 							auto param = dsp_a->getParam(RTLIL::escape_id(it)); | ||||
| 							if (param.size() > 1) { | ||||
| 								mode_bits.insert(mode_bits.end(), param.bits.begin(), param.bits.end()); | ||||
| 							} else { | ||||
| 								mode_bits.push_back(param.bits[0]); | ||||
| 							} | ||||
| 						} | ||||
| 						mode_bits_size += MODE_BITS_EXTENSION_SIZE; | ||||
| 					} else { | ||||
| 						// Enable the fractured mode by connecting the control
 | ||||
| 						// port.
 | ||||
| 						simd->setPort(RTLIL::escape_id("f_mode"), RTLIL::S1); | ||||
| 					} | ||||
| 					simd->setParam(RTLIL::escape_id("MODE_BITS"), RTLIL::Const(mode_bits)); | ||||
| 					log_assert(mode_bits.size() == mode_bits_size); | ||||
| 
 | ||||
| 					// Handle the "is_inferred" attribute. If one of the fragments
 | ||||
| 					// is not inferred mark the whole DSP as not inferred
 | ||||
| 					bool is_inferred_a = | ||||
| 					  dsp_a->has_attribute(RTLIL::escape_id("is_inferred")) ? dsp_a->get_bool_attribute(RTLIL::escape_id("is_inferred")) : false; | ||||
| 					bool is_inferred_b = | ||||
| 					  dsp_b->has_attribute(RTLIL::escape_id("is_inferred")) ? dsp_b->get_bool_attribute(RTLIL::escape_id("is_inferred")) : false; | ||||
| 
 | ||||
| 					simd->set_bool_attribute(RTLIL::escape_id("is_inferred"), is_inferred_a && is_inferred_b); | ||||
| 
 | ||||
| 					// Mark DSP parts for removal
 | ||||
| 					cellsToRemove.push_back(dsp_a); | ||||
| 					cellsToRemove.push_back(dsp_b); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Remove old cells
 | ||||
| 			for (const auto &cell : cellsToRemove) { | ||||
| 				module->remove(const_cast<RTLIL::Cell *>(cell)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Clear
 | ||||
| 		m_SigMap.clear(); | ||||
| 	} | ||||
| 
 | ||||
| 	// ..........................................
 | ||||
| 
 | ||||
| 	/// Looks up port width and direction in the cell definition and returns it.
 | ||||
| 	/// Returns (0, false) if it cannot be determined.
 | ||||
| 	std::pair<size_t, bool> getPortInfo(RTLIL::Cell *a_Cell, RTLIL::IdString a_Port) | ||||
| 	{ | ||||
| 		if (!a_Cell->known()) { | ||||
| 			return std::make_pair(0, false); | ||||
| 		} | ||||
| 
 | ||||
| 		// Get the module defining the cell (the previous condition ensures
 | ||||
| 		// that the pointers are valid)
 | ||||
| 		RTLIL::Module *mod = a_Cell->module->design->module(a_Cell->type); | ||||
| 		if (mod == nullptr) { | ||||
| 			return std::make_pair(0, false); | ||||
| 		} | ||||
| 
 | ||||
| 		// Get the wire representing the port
 | ||||
| 		RTLIL::Wire *wire = mod->wire(a_Port); | ||||
| 		if (wire == nullptr) { | ||||
| 			return std::make_pair(0, false); | ||||
| 		} | ||||
| 
 | ||||
| 		return std::make_pair(wire->width, wire->port_output); | ||||
| 	} | ||||
| 
 | ||||
| 	/// Given a DSP cell populates and returns a DspConfig struct for it.
 | ||||
| 	DspConfig getDspConfig(RTLIL::Cell *a_Cell) | ||||
| 	{ | ||||
| 		DspConfig config; | ||||
| 
 | ||||
| 		string cell_type = a_Cell->type.str(); | ||||
| 		string suffix = m_SisdDspType_cfg_params_suffix; | ||||
| 
 | ||||
| 		bool use_cfg_params = cell_type.size() >= suffix.size() && 0 == cell_type.compare(cell_type.size() - suffix.size(), suffix.size(), suffix); | ||||
| 
 | ||||
| 		std::vector<std::pair<std::string, std::string>> DspCfgPorts = m_DspCfgPorts; | ||||
| 		if (!use_cfg_params) | ||||
| 			DspCfgPorts.insert(DspCfgPorts.end(), m_DspCfgPorts_expand.begin(), m_DspCfgPorts_expand.end()); | ||||
| 
 | ||||
| 		config.use_cfg_params = use_cfg_params; | ||||
| 
 | ||||
| 		for (const auto &it : DspCfgPorts) { | ||||
| 			auto port = RTLIL::escape_id(it.first); | ||||
| 
 | ||||
| 			// Port unconnected
 | ||||
| 			if (!a_Cell->hasPort(port)) { | ||||
| 				config.connections[port] = RTLIL::SigSpec(RTLIL::Sx); | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			// Get the port connection and map it to unique SigBits
 | ||||
| 			const auto &orgSigSpec = a_Cell->getPort(port); | ||||
| 			const auto &orgSigBits = orgSigSpec.bits(); | ||||
| 
 | ||||
| 			RTLIL::SigSpec newSigSpec; | ||||
| 			for (size_t i = 0; i < orgSigBits.size(); ++i) { | ||||
| 				auto newSigBit = m_SigMap(orgSigBits[i]); | ||||
| 				newSigSpec.append(newSigBit); | ||||
| 			} | ||||
| 
 | ||||
| 			// Store
 | ||||
| 			config.connections[port] = newSigSpec; | ||||
| 		} | ||||
| 
 | ||||
| 		return config; | ||||
| 	} | ||||
| 
 | ||||
| } QlDspSimdPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
							
								
								
									
										265
									
								
								techlibs/quicklogic/qlf_k6n10f/dsp_final_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								techlibs/quicklogic/qlf_k6n10f/dsp_final_map.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,265 @@ | |||
| // Copyright 2020-2022 F4PGA Authors
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| //
 | ||||
| // SPDX-License-Identifier: Apache-2.0
 | ||||
| 
 | ||||
| module dsp_t1_20x18x64_cfg_ports ( | ||||
|     input  [19:0] a_i, | ||||
|     input  [17:0] b_i, | ||||
|     input  [ 5:0] acc_fir_i, | ||||
|     output [37:0] z_o, | ||||
|     output [17:0] dly_b_o, | ||||
| 
 | ||||
|     input         clock_i, | ||||
|     input         reset_i, | ||||
| 
 | ||||
|     input  [2:0]  feedback_i, | ||||
|     input         load_acc_i, | ||||
|     input         unsigned_a_i, | ||||
|     input         unsigned_b_i, | ||||
| 
 | ||||
|     input  [2:0]  output_select_i, | ||||
|     input         saturate_enable_i, | ||||
|     input  [5:0]  shift_right_i, | ||||
|     input         round_i, | ||||
|     input         subtract_i, | ||||
|     input         register_inputs_i | ||||
| ); | ||||
| 
 | ||||
|     parameter [19:0] COEFF_0 = 20'd0; | ||||
|     parameter [19:0] COEFF_1 = 20'd0; | ||||
|     parameter [19:0] COEFF_2 = 20'd0; | ||||
|     parameter [19:0] COEFF_3 = 20'd0; | ||||
| 
 | ||||
|     QL_DSP2 # ( | ||||
|         .MODE_BITS          ({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) | ||||
|     ) _TECHMAP_REPLACE_ ( | ||||
|         .a                  (a_i), | ||||
|         .b                  (b_i), | ||||
|         .acc_fir            (acc_fir_i), | ||||
|         .z                  (z_o), | ||||
|         .dly_b              (dly_b_o), | ||||
| 
 | ||||
|         .clk                (clock_i), | ||||
|         .reset              (reset_i), | ||||
| 
 | ||||
|         .feedback           (feedback_i), | ||||
|         .load_acc           (load_acc_i), | ||||
|         .unsigned_a         (unsigned_a_i), | ||||
|         .unsigned_b         (unsigned_b_i), | ||||
| 
 | ||||
|         .f_mode             (1'b0), // No fracturation
 | ||||
|         .output_select      (output_select_i), | ||||
|         .saturate_enable    (saturate_enable_i), | ||||
|         .shift_right        (shift_right_i), | ||||
|         .round              (round_i), | ||||
|         .subtract           (subtract_i), | ||||
|         .register_inputs    (register_inputs_i) | ||||
|     ); | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| module dsp_t1_10x9x32_cfg_ports ( | ||||
|     input  [ 9:0] a_i, | ||||
|     input  [ 8:0] b_i, | ||||
|     input  [ 5:0] acc_fir_i, | ||||
|     output [18:0] z_o, | ||||
|     output [ 8:0] dly_b_o, | ||||
| 
 | ||||
|     (* clkbuf_sink *) | ||||
|     input         clock_i, | ||||
|     input         reset_i, | ||||
| 
 | ||||
|     input  [2:0]  feedback_i, | ||||
|     input         load_acc_i, | ||||
|     input         unsigned_a_i, | ||||
|     input         unsigned_b_i, | ||||
| 
 | ||||
|     input  [2:0]  output_select_i, | ||||
|     input         saturate_enable_i, | ||||
|     input  [5:0]  shift_right_i, | ||||
|     input         round_i, | ||||
|     input         subtract_i, | ||||
|     input         register_inputs_i | ||||
| ); | ||||
| 
 | ||||
|     parameter [9:0] COEFF_0 = 10'd0; | ||||
|     parameter [9:0] COEFF_1 = 10'd0; | ||||
|     parameter [9:0] COEFF_2 = 10'd0; | ||||
|     parameter [9:0] COEFF_3 = 10'd0; | ||||
| 
 | ||||
|     wire [37:0] z; | ||||
|     wire [17:0] dly_b; | ||||
| 
 | ||||
|     QL_DSP2 # ( | ||||
|         .MODE_BITS          ({10'd0, COEFF_3, | ||||
|                               10'd0, COEFF_2, | ||||
|                               10'd0, COEFF_1, | ||||
|                               10'd0, COEFF_0}) | ||||
|     ) _TECHMAP_REPLACE_ ( | ||||
|         .a                  ({10'd0, a_i}), | ||||
|         .b                  ({ 9'd0, b_i}), | ||||
|         .acc_fir            (acc_fir_i), | ||||
|         .z                  (z), | ||||
|         .dly_b              (dly_b), | ||||
| 
 | ||||
|         .clk                (clock_i), | ||||
|         .reset              (reset_i), | ||||
| 
 | ||||
|         .feedback           (feedback_i), | ||||
|         .load_acc           (load_acc_i), | ||||
|         .unsigned_a         (unsigned_a_i), | ||||
|         .unsigned_b         (unsigned_b_i), | ||||
| 
 | ||||
|         .f_mode             (1'b1), // Enable fractuation, Use the lower half
 | ||||
|         .output_select      (output_select_i), | ||||
|         .saturate_enable    (saturate_enable_i), | ||||
|         .shift_right        (shift_right_i), | ||||
|         .round              (round_i), | ||||
|         .subtract           (subtract_i), | ||||
|         .register_inputs    (register_inputs_i) | ||||
|     ); | ||||
| 
 | ||||
|     assign z_o = z[18:0]; | ||||
|     assign dly_b_o = dly_b_o[8:0]; | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| module dsp_t1_20x18x64_cfg_params ( | ||||
|     input  [19:0] a_i, | ||||
|     input  [17:0] b_i, | ||||
|     input  [ 5:0] acc_fir_i, | ||||
|     output [37:0] z_o, | ||||
|     output [17:0] dly_b_o, | ||||
| 
 | ||||
|     input         clock_i, | ||||
|     input         reset_i, | ||||
| 
 | ||||
|     input  [2:0]  feedback_i, | ||||
|     input         load_acc_i, | ||||
|     input         unsigned_a_i, | ||||
|     input         unsigned_b_i, | ||||
|     input         subtract_i | ||||
| ); | ||||
| 
 | ||||
|     parameter [19:0] COEFF_0 = 20'd0; | ||||
|     parameter [19:0] COEFF_1 = 20'd0; | ||||
|     parameter [19:0] COEFF_2 = 20'd0; | ||||
|     parameter [19:0] COEFF_3 = 20'd0; | ||||
| 
 | ||||
|     parameter [2:0] OUTPUT_SELECT   = 3'd0; | ||||
|     parameter [0:0] SATURATE_ENABLE = 1'd0; | ||||
|     parameter [5:0] SHIFT_RIGHT     = 6'd0; | ||||
|     parameter [0:0] ROUND           = 1'd0; | ||||
|     parameter [0:0] REGISTER_INPUTS = 1'd0; | ||||
| 
 | ||||
|     QL_DSP3 # ( | ||||
|         .MODE_BITS ({ | ||||
|             REGISTER_INPUTS, | ||||
|             ROUND, | ||||
|             SHIFT_RIGHT, | ||||
|             SATURATE_ENABLE, | ||||
|             OUTPUT_SELECT, | ||||
|             1'b0, // Not fractured
 | ||||
|             COEFF_3, | ||||
|             COEFF_2, | ||||
|             COEFF_1, | ||||
|             COEFF_0 | ||||
|         }) | ||||
|     ) _TECHMAP_REPLACE_ ( | ||||
|         .a                  (a_i), | ||||
|         .b                  (b_i), | ||||
|         .acc_fir            (acc_fir_i), | ||||
|         .z                  (z_o), | ||||
|         .dly_b              (dly_b_o), | ||||
| 
 | ||||
|         .clk                (clock_i), | ||||
|         .reset              (reset_i), | ||||
| 
 | ||||
|         .feedback           (feedback_i), | ||||
|         .load_acc           (load_acc_i), | ||||
|         .unsigned_a         (unsigned_a_i), | ||||
|         .unsigned_b         (unsigned_b_i), | ||||
|         .subtract           (subtract_i) | ||||
|     ); | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| module dsp_t1_10x9x32_cfg_params ( | ||||
|     input  [ 9:0] a_i, | ||||
|     input  [ 8:0] b_i, | ||||
|     input  [ 5:0] acc_fir_i, | ||||
|     output [18:0] z_o, | ||||
|     output [ 8:0] dly_b_o, | ||||
| 
 | ||||
|     (* clkbuf_sink *) | ||||
|     input         clock_i, | ||||
|     input         reset_i, | ||||
| 
 | ||||
|     input  [2:0]  feedback_i, | ||||
|     input         load_acc_i, | ||||
|     input         unsigned_a_i, | ||||
|     input         unsigned_b_i, | ||||
|     input         subtract_i | ||||
| ); | ||||
| 
 | ||||
|     parameter [9:0] COEFF_0 = 10'd0; | ||||
|     parameter [9:0] COEFF_1 = 10'd0; | ||||
|     parameter [9:0] COEFF_2 = 10'd0; | ||||
|     parameter [9:0] COEFF_3 = 10'd0; | ||||
| 
 | ||||
|     parameter [2:0] OUTPUT_SELECT   = 3'd0; | ||||
|     parameter [0:0] SATURATE_ENABLE = 1'd0; | ||||
|     parameter [5:0] SHIFT_RIGHT     = 6'd0; | ||||
|     parameter [0:0] ROUND           = 1'd0; | ||||
|     parameter [0:0] REGISTER_INPUTS = 1'd0; | ||||
| 
 | ||||
|     wire [37:0] z; | ||||
|     wire [17:0] dly_b; | ||||
| 
 | ||||
|     QL_DSP3 # ( | ||||
|         .MODE_BITS  ({ | ||||
|             REGISTER_INPUTS, | ||||
|             ROUND, | ||||
|             SHIFT_RIGHT, | ||||
|             SATURATE_ENABLE, | ||||
|             OUTPUT_SELECT, | ||||
|             1'b1, // Fractured
 | ||||
|             10'd0, COEFF_3, | ||||
|             10'd0, COEFF_2, | ||||
|             10'd0, COEFF_1, | ||||
|             10'd0, COEFF_0 | ||||
|         }) | ||||
|     ) _TECHMAP_REPLACE_ ( | ||||
|         .a                  ({10'd0, a_i}), | ||||
|         .b                  ({ 9'd0, b_i}), | ||||
|         .acc_fir            (acc_fir_i), | ||||
|         .z                  (z), | ||||
|         .dly_b              (dly_b), | ||||
| 
 | ||||
|         .clk                (clock_i), | ||||
|         .reset              (reset_i), | ||||
| 
 | ||||
|         .feedback           (feedback_i), | ||||
|         .load_acc           (load_acc_i), | ||||
|         .unsigned_a         (unsigned_a_i), | ||||
|         .unsigned_b         (unsigned_b_i), | ||||
|         .subtract           (subtract_i) | ||||
|     ); | ||||
| 
 | ||||
|     assign z_o = z[18:0]; | ||||
|     assign dly_b_o = dly_b_o[8:0]; | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
							
								
								
									
										147
									
								
								techlibs/quicklogic/qlf_k6n10f/dsp_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								techlibs/quicklogic/qlf_k6n10f/dsp_map.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,147 @@ | |||
| // Copyright 2020-2022 F4PGA Authors
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| //
 | ||||
| // SPDX-License-Identifier: Apache-2.0
 | ||||
| 
 | ||||
| module \$__QL_MUL20X18 (input [19:0] A, input [17:0] B, output [37:0] Y); | ||||
|     parameter A_SIGNED = 0; | ||||
|     parameter B_SIGNED = 0; | ||||
|     parameter A_WIDTH = 0; | ||||
|     parameter B_WIDTH = 0; | ||||
|     parameter Y_WIDTH = 0; | ||||
| 
 | ||||
|     wire [19:0] a; | ||||
|     wire [17:0] b; | ||||
|     wire [37:0] z; | ||||
| 
 | ||||
|     assign a = (A_WIDTH == 20) ? A : | ||||
|                (A_SIGNED) ? {{(20 - A_WIDTH){A[A_WIDTH-1]}}, A} : | ||||
|                             {{(20 - A_WIDTH){1'b0}},         A}; | ||||
| 
 | ||||
|     assign b = (B_WIDTH == 18) ? B : | ||||
|                (B_SIGNED) ? {{(18 - B_WIDTH){B[B_WIDTH-1]}}, B} : | ||||
|                             {{(18 - B_WIDTH){1'b0}},         B}; | ||||
| 
 | ||||
|     generate if (`USE_DSP_CFG_PARAMS == 0) begin | ||||
|         (* is_inferred=1 *) | ||||
|         dsp_t1_20x18x64_cfg_ports _TECHMAP_REPLACE_ ( | ||||
|             .a_i                (a), | ||||
|             .b_i                (b), | ||||
|             .acc_fir_i          (6'd0), | ||||
|             .z_o                (z), | ||||
| 
 | ||||
|             .feedback_i         (3'd0), | ||||
|             .load_acc_i         (1'b0), | ||||
|             .unsigned_a_i       (!A_SIGNED), | ||||
|             .unsigned_b_i       (!B_SIGNED), | ||||
| 
 | ||||
|             .output_select_i    (3'd0), | ||||
|             .saturate_enable_i  (1'b0), | ||||
|             .shift_right_i      (6'd0), | ||||
|             .round_i            (1'b0), | ||||
|             .subtract_i         (1'b0), | ||||
|             .register_inputs_i  (1'b0) | ||||
|         ); | ||||
|     end else begin | ||||
|         (* is_inferred=1 *) | ||||
|         dsp_t1_20x18x64_cfg_params #( | ||||
|             .OUTPUT_SELECT      (3'd0), | ||||
|             .SATURATE_ENABLE    (1'b0), | ||||
|             .SHIFT_RIGHT        (6'd0), | ||||
|             .ROUND              (1'b0), | ||||
|             .REGISTER_INPUTS    (1'b0) | ||||
|         ) TECHMAP_REPLACE_ ( | ||||
|             .a_i                (a), | ||||
|             .b_i                (b), | ||||
|             .acc_fir_i          (6'd0), | ||||
|             .z_o                (z), | ||||
| 
 | ||||
|             .feedback_i         (3'd0), | ||||
|             .load_acc_i         (1'b0), | ||||
|             .unsigned_a_i       (!A_SIGNED), | ||||
|             .unsigned_b_i       (!B_SIGNED), | ||||
| 
 | ||||
|             .subtract_i         (1'b0) | ||||
|         ); | ||||
|     end endgenerate | ||||
| 
 | ||||
|     assign Y = z; | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| module \$__QL_MUL10X9 (input [9:0] A, input [8:0] B, output [18:0] Y); | ||||
|     parameter A_SIGNED = 0; | ||||
|     parameter B_SIGNED = 0; | ||||
|     parameter A_WIDTH = 0; | ||||
|     parameter B_WIDTH = 0; | ||||
|     parameter Y_WIDTH = 0; | ||||
| 
 | ||||
|     wire [ 9:0] a; | ||||
|     wire [ 8:0] b; | ||||
|     wire [18:0] z; | ||||
| 
 | ||||
|     assign a = (A_WIDTH == 10) ? A : | ||||
|                (A_SIGNED) ? {{(10 - A_WIDTH){A[A_WIDTH-1]}}, A} : | ||||
|                             {{(10 - A_WIDTH){1'b0}},         A}; | ||||
| 
 | ||||
|     assign b = (B_WIDTH ==  9) ? B : | ||||
|                (B_SIGNED) ? {{( 9 - B_WIDTH){B[B_WIDTH-1]}}, B} : | ||||
|                             {{( 9 - B_WIDTH){1'b0}},         B}; | ||||
| 
 | ||||
|     generate if (`USE_DSP_CFG_PARAMS == 0) begin | ||||
|         (* is_inferred=1 *) | ||||
|         dsp_t1_10x9x32_cfg_ports _TECHMAP_REPLACE_ ( | ||||
|             .a_i                (a), | ||||
|             .b_i                (b), | ||||
|             .acc_fir_i          (6'd0), | ||||
|             .z_o                (z), | ||||
| 
 | ||||
|             .feedback_i         (3'd0), | ||||
|             .load_acc_i         (1'b0), | ||||
|             .unsigned_a_i       (!A_SIGNED), | ||||
|             .unsigned_b_i       (!B_SIGNED), | ||||
| 
 | ||||
|             .output_select_i    (3'd0), | ||||
|             .saturate_enable_i  (1'b0), | ||||
|             .shift_right_i      (6'd0), | ||||
|             .round_i            (1'b0), | ||||
|             .subtract_i         (1'b0), | ||||
|             .register_inputs_i  (1'b0) | ||||
|         ); | ||||
|     end else begin | ||||
|         (* is_inferred=1 *) | ||||
|         dsp_t1_10x9x32_cfg_params #( | ||||
|             .OUTPUT_SELECT      (3'd0), | ||||
|             .SATURATE_ENABLE    (1'b0), | ||||
|             .SHIFT_RIGHT        (6'd0), | ||||
|             .ROUND              (1'b0), | ||||
|             .REGISTER_INPUTS    (1'b0) | ||||
|         ) TECHMAP_REPLACE_ ( | ||||
|             .a_i                (a), | ||||
|             .b_i                (b), | ||||
|             .acc_fir_i          (6'd0), | ||||
|             .z_o                (z), | ||||
| 
 | ||||
|             .feedback_i         (3'd0), | ||||
|             .load_acc_i         (1'b0), | ||||
|             .unsigned_a_i       (!A_SIGNED), | ||||
|             .unsigned_b_i       (!B_SIGNED), | ||||
| 
 | ||||
|             .subtract_i         (1'b0) | ||||
|         ); | ||||
|     end endgenerate | ||||
| 
 | ||||
|     assign Y = z; | ||||
| 
 | ||||
| endmodule | ||||
							
								
								
									
										5753
									
								
								techlibs/quicklogic/qlf_k6n10f/dsp_sim.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5753
									
								
								techlibs/quicklogic/qlf_k6n10f/dsp_sim.v
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -46,6 +46,15 @@ struct SynthQuickLogicPass : public ScriptPass { | |||
| 		log("        - pp3: PolarPro 3 \n"); | ||||
| 		log("        - qlf_k6n10f: K6N10f\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nodsp\n"); | ||||
| 		log("        do not use dsp_t1_* to implement multipliers and associated logic\n"); | ||||
| 		log("        (qlf_k6n10f only).\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -use_dsp_cfg_params\n"); | ||||
| 		log("        By default use DSP blocks with configuration bits available at module\n"); | ||||
| 		log("        ports. Specifying this forces usage of DSP block with configuration\n"); | ||||
| 		log("        bits available as module parameters.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nocarry\n"); | ||||
| 		log("        do not use adder_carry cells in output netlist.\n"); | ||||
| 		log("\n"); | ||||
|  | @ -74,7 +83,7 @@ struct SynthQuickLogicPass : public ScriptPass { | |||
| 	} | ||||
| 
 | ||||
| 	string top_opt, blif_file, edif_file, family, currmodule, verilog_file, lib_path; | ||||
| 	bool abc9, inferAdder, nobram, bramTypes; | ||||
| 	bool abc9, inferAdder, nobram, bramTypes, dsp; | ||||
| 
 | ||||
| 	void clear_flags() override | ||||
| 	{ | ||||
|  | @ -89,6 +98,7 @@ struct SynthQuickLogicPass : public ScriptPass { | |||
| 		nobram = false; | ||||
| 		bramTypes = false; | ||||
| 		lib_path = "+/quicklogic/"; | ||||
| 		dsp = true; | ||||
| 	} | ||||
| 
 | ||||
| 	void set_scratchpad_defaults(RTLIL::Design *design) { | ||||
|  | @ -149,6 +159,14 @@ struct SynthQuickLogicPass : public ScriptPass { | |||
| 				bramTypes = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-nodsp" || args[argidx] == "-no_dsp") { | ||||
| 				dsp = false; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-use_dsp_cfg_params") { | ||||
| 				use_dsp_cfg_params = " -use_dsp_cfg_params"; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
|  | @ -184,6 +202,8 @@ struct SynthQuickLogicPass : public ScriptPass { | |||
| 				read_simlibs += stringf(" %sqlf_k6n10f/brams_sim.v", lib_path.c_str()); | ||||
| 				if (bramTypes) | ||||
| 					read_simlibs += stringf(" %sqlf_k6n10f/bram_types_sim.v", lib_path.c_str()); | ||||
| 				if (dsp) | ||||
| 					read_simlibs += stringf(" %sqlf_k6n10f/dsp_sim.v", lib_path.c_str()); | ||||
| 			} | ||||
| 			run(read_simlibs); | ||||
| 			run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); | ||||
|  | @ -208,6 +228,24 @@ struct SynthQuickLogicPass : public ScriptPass { | |||
| 			run("share"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("map_dsp", "(for qlf_k6n10f, skip if -nodsp)") | ||||
| 				&& ((dsp && family == "qlf_k6n10f") || help_mode)) { | ||||
| 			run("wreduce t:$mul"); | ||||
| 			run("ql_dsp_macc" + use_dsp_cfg_params); | ||||
| 
 | ||||
| 			run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=20 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=11 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__QL_MUL20X18"); | ||||
| 			run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=10 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__QL_MUL10X9"); | ||||
| 			run("chtype -set $mul t:$__soft_mul"); | ||||
| 				 | ||||
| 			if (use_dsp_cfg_params.empty()) | ||||
| 				run("techmap -map " + lib_path + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=0"); | ||||
| 			else | ||||
| 				run("techmap -map " + lib_path + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=1"); | ||||
| 			run("ql_dsp_simd"); | ||||
| 			run("techmap -map " + lib_path + family + "/dsp_final_map.v"); | ||||
| 			run("ql_dsp_io_regs"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("coarse")) { | ||||
| 			run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); | ||||
| 			run("opt_expr"); | ||||
|  | @ -219,15 +257,16 @@ struct SynthQuickLogicPass : public ScriptPass { | |||
| 			run("opt_clean"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("map_bram", "(for qlf_k6n10f, skip if -no_bram)") && (help_mode || family == "qlf_k6n10f")) { | ||||
| 		if (check_label("map_bram", "(for qlf_k6n10f, skip if -no_bram)")) { | ||||
| 			if(family == "qlf_k6n10f" || help_mode) | ||||
| 			run("memory_libmap -lib " + lib_path + family + "/libmap_brams.txt"); | ||||
| 			run("ql_bram_merge"); | ||||
| 			run("techmap -map " + lib_path + family + "/libmap_brams_map.v"); | ||||
| 			run("techmap -autoproc -map " + lib_path + family + "/brams_map.v"); | ||||
| 			run("techmap -map " + lib_path + family + "/brams_final_map.v"); | ||||
| 
 | ||||
| 			if (help_mode || bramTypes) { | ||||
| 				run("ql_bram_types"); | ||||
| 			if (bramTypes || help_mode) { | ||||
| 				run("ql_bram_types", "(if -bramtypes)"); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue