mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-03 21:09:12 +00:00 
			
		
		
		
	peepopt: add formal only peepopt to rewrite latches to ffs in clock gates
* this is gated behind the -formalclk flag, which also disables the other synthesis focused optimizations
This commit is contained in:
		
							parent
							
								
									d08bf671b2
								
							
						
					
					
						commit
						2cb3b6e9b8
					
				
					 3 changed files with 81 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -57,6 +57,7 @@ PEEPOPT_PATTERN  = passes/pmgen/peepopt_shiftmul_right.pmg
 | 
			
		|||
PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftmul_left.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftadd.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
 | 
			
		||||
PEEPOPT_PATTERN += passes/pmgen/peepopt_formal_clockgateff.pmg
 | 
			
		||||
 | 
			
		||||
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
 | 
			
		||||
	$(P) mkdir -p passes/pmgen && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,7 @@ struct PeepoptPass : public Pass {
 | 
			
		|||
		log("\n");
 | 
			
		||||
		log("This pass applies a collection of peephole optimizers to the current design.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("This pass employs the following rules:\n");
 | 
			
		||||
		log("This pass employs the following rules by default:\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("   * muldiv - Replace (A*B)/B with A\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -57,14 +57,26 @@ struct PeepoptPass : public Pass {
 | 
			
		|||
		log("                limits the amount of padding to a multiple of the data, \n");
 | 
			
		||||
		log("                to avoid high resource usage from large temporary MUX trees.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("If -formalclk is specified it instead employs the following rules:\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("   * clockgateff - Replace latch based clock gating patterns with a flip-flop\n");
 | 
			
		||||
		log("                   based pattern to prevent combinational paths from the\n");
 | 
			
		||||
		log("                   output to the enable input after running clk2fflogic.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
	}
 | 
			
		||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) override
 | 
			
		||||
	{
 | 
			
		||||
		log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n");
 | 
			
		||||
 | 
			
		||||
		bool formalclk = false;
 | 
			
		||||
 | 
			
		||||
		size_t argidx;
 | 
			
		||||
		for (argidx = 1; argidx < args.size(); argidx++)
 | 
			
		||||
		{
 | 
			
		||||
			if (args[argidx] == "-formalclk") {
 | 
			
		||||
				formalclk = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		extra_args(args, argidx, design);
 | 
			
		||||
| 
						 | 
				
			
			@ -86,10 +98,14 @@ struct PeepoptPass : public Pass {
 | 
			
		|||
 | 
			
		||||
				pm.setup(module->selected_cells());
 | 
			
		||||
 | 
			
		||||
				pm.run_shiftadd();
 | 
			
		||||
				pm.run_shiftmul_right();
 | 
			
		||||
				pm.run_shiftmul_left();
 | 
			
		||||
				pm.run_muldiv();
 | 
			
		||||
				if (formalclk) {
 | 
			
		||||
					pm.run_formal_clockgateff();
 | 
			
		||||
				} else {
 | 
			
		||||
					pm.run_shiftadd();
 | 
			
		||||
					pm.run_shiftmul_right();
 | 
			
		||||
					pm.run_shiftmul_left();
 | 
			
		||||
					pm.run_muldiv();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										59
									
								
								passes/pmgen/peepopt_formal_clockgateff.pmg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								passes/pmgen/peepopt_formal_clockgateff.pmg
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
pattern formal_clockgateff
 | 
			
		||||
 | 
			
		||||
// Detects the most common clock gating pattern using a latch and replaces it
 | 
			
		||||
// with a functionally equivalent pattern based on a flip-flop. The latch
 | 
			
		||||
// based pattern has a combinational path from the enable input to output after
 | 
			
		||||
// clk2fflogic, but this is a stable loop and the flip-flop based pattern does
 | 
			
		||||
// not exhibit this.
 | 
			
		||||
//
 | 
			
		||||
// This optimization is suitable for formal to prevent false comb loops, but
 | 
			
		||||
// should not be used for synthesis where the latch is an intentional choice
 | 
			
		||||
//
 | 
			
		||||
// Latch style:
 | 
			
		||||
// always @* if (!clk_i) latched_en = en;
 | 
			
		||||
// assign gated_clk_o = latched_en & clk_i;
 | 
			
		||||
//
 | 
			
		||||
// Flip-flop style:
 | 
			
		||||
// always @(posedge clk) flopped_en <= en;
 | 
			
		||||
// assign gated_clk_o = flopped_en & clk_i;
 | 
			
		||||
 | 
			
		||||
state <SigSpec> clk en latched_en gated_clk
 | 
			
		||||
state <IdString> latched_en_port_name
 | 
			
		||||
 | 
			
		||||
match latch
 | 
			
		||||
	select latch->type == $dlatch
 | 
			
		||||
	select param(latch, \WIDTH) == 1
 | 
			
		||||
	select param(latch, \EN_POLARITY).as_bool() == false
 | 
			
		||||
	set clk port(latch, \EN)
 | 
			
		||||
	set en port(latch, \D)
 | 
			
		||||
	set latched_en port(latch, \Q)
 | 
			
		||||
endmatch
 | 
			
		||||
 | 
			
		||||
match and_gate
 | 
			
		||||
	select and_gate->type.in($and, $logic_and)
 | 
			
		||||
	select param(and_gate, \A_WIDTH) == 1
 | 
			
		||||
	select param(and_gate, \B_WIDTH) == 1
 | 
			
		||||
	select param(and_gate, \Y_WIDTH) == 1
 | 
			
		||||
	choice <IdString> clk_port {\A, \B}
 | 
			
		||||
	define <IdString> latch_port {clk_port == \A ? \B : \A}
 | 
			
		||||
	index <SigSpec> port(and_gate, clk_port) === clk
 | 
			
		||||
	index <SigSpec> port(and_gate, latch_port) === latched_en
 | 
			
		||||
	set gated_clk port(and_gate, \Y)
 | 
			
		||||
	set latched_en_port_name latch_port
 | 
			
		||||
endmatch
 | 
			
		||||
 | 
			
		||||
code
 | 
			
		||||
	log("replacing clock gate pattern in %s with ff: latch=%s, and=%s\n",
 | 
			
		||||
		log_id(module), log_id(latch), log_id(and_gate));
 | 
			
		||||
 | 
			
		||||
	// Add a flip-flop and rewire the AND gate to use the output of this flop
 | 
			
		||||
	// instead of the latch. We don't delete the latch in case its output is
 | 
			
		||||
	// used to drive other nodes. If it isn't, it will be trivially removed by
 | 
			
		||||
	// clean
 | 
			
		||||
	SigSpec flopped_en = module->addWire(NEW_ID);
 | 
			
		||||
	module->addDff(NEW_ID, clk, en, flopped_en, true, latch->get_src_attribute());
 | 
			
		||||
	and_gate->setPort(latched_en_port_name, flopped_en);
 | 
			
		||||
	did_something = true;
 | 
			
		||||
 | 
			
		||||
	accept;
 | 
			
		||||
endcode
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue