mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-03 21:09:12 +00:00 
			
		
		
		
	Separate out CREG packing into new pattern, to avoid conflict with PREG
This commit is contained in:
		
							parent
							
								
									26a6c55665
								
							
						
					
					
						commit
						15dfbc8125
					
				
					 4 changed files with 273 additions and 46 deletions
				
			
		| 
						 | 
					@ -22,8 +22,9 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
 | 
				
			||||||
# --------------------------------------
 | 
					# --------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OBJS += passes/pmgen/xilinx_dsp.o
 | 
					OBJS += passes/pmgen/xilinx_dsp.o
 | 
				
			||||||
passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp_cascade_pm.h
 | 
					passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp_CREG_pm.h passes/pmgen/xilinx_dsp_cascade_pm.h
 | 
				
			||||||
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h))
 | 
					$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h))
 | 
				
			||||||
 | 
					$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_CREG_pm.h))
 | 
				
			||||||
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h))
 | 
					$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# --------------------------------------
 | 
					# --------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
bool did_something;
 | 
					bool did_something;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "passes/pmgen/xilinx_dsp_pm.h"
 | 
					#include "passes/pmgen/xilinx_dsp_pm.h"
 | 
				
			||||||
 | 
					#include "passes/pmgen/xilinx_dsp_CREG_pm.h"
 | 
				
			||||||
#include "passes/pmgen/xilinx_dsp_cascade_pm.h"
 | 
					#include "passes/pmgen/xilinx_dsp_cascade_pm.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static Cell* addDsp(Module *module) {
 | 
					static Cell* addDsp(Module *module) {
 | 
				
			||||||
| 
						 | 
					@ -63,7 +64,7 @@ static Cell* addDsp(Module *module) {
 | 
				
			||||||
	return cell;
 | 
						return cell;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pack_xilinx_simd(Module *module, const std::vector<Cell*> &selected_cells)
 | 
					void xilinx_simd_pack(Module *module, const std::vector<Cell*> &selected_cells)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::deque<Cell*> simd12_add, simd12_sub;
 | 
						std::deque<Cell*> simd12_add, simd12_sub;
 | 
				
			||||||
	std::deque<Cell*> simd24_add, simd24_sub;
 | 
						std::deque<Cell*> simd24_add, simd24_sub;
 | 
				
			||||||
| 
						 | 
					@ -255,21 +256,18 @@ void pack_xilinx_simd(Module *module, const std::vector<Cell*> &selected_cells)
 | 
				
			||||||
	g24(simd24_sub);
 | 
						g24(simd24_sub);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void xilinx_dsp_pack(xilinx_dsp_pm &pm)
 | 
				
			||||||
void pack_xilinx_dsp(xilinx_dsp_pm &pm)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto &st = pm.st_xilinx_dsp_pack;
 | 
						auto &st = pm.st_xilinx_dsp_pack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp));
 | 
						log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log_debug("\n");
 | 
					 | 
				
			||||||
	log_debug("preAdd:     %s\n", log_id(st.preAdd, "--"));
 | 
						log_debug("preAdd:     %s\n", log_id(st.preAdd, "--"));
 | 
				
			||||||
	log_debug("ffAD:       %s %s %s\n", log_id(st.ffAD, "--"), log_id(st.ffADcemux, "--"), log_id(st.ffADrstmux, "--"));
 | 
						log_debug("ffAD:       %s %s %s\n", log_id(st.ffAD, "--"), log_id(st.ffADcemux, "--"), log_id(st.ffADrstmux, "--"));
 | 
				
			||||||
	log_debug("ffA2:       %s %s %s\n", log_id(st.ffA2, "--"), log_id(st.ffA2cemux, "--"), log_id(st.ffA2rstmux, "--"));
 | 
						log_debug("ffA2:       %s %s %s\n", log_id(st.ffA2, "--"), log_id(st.ffA2cemux, "--"), log_id(st.ffA2rstmux, "--"));
 | 
				
			||||||
	log_debug("ffA1:       %s %s %s\n", log_id(st.ffA1, "--"), log_id(st.ffA1cemux, "--"), log_id(st.ffA1rstmux, "--"));
 | 
						log_debug("ffA1:       %s %s %s\n", log_id(st.ffA1, "--"), log_id(st.ffA1cemux, "--"), log_id(st.ffA1rstmux, "--"));
 | 
				
			||||||
	log_debug("ffB2:       %s %s %s\n", log_id(st.ffB2, "--"), log_id(st.ffB2cemux, "--"), log_id(st.ffB2rstmux, "--"));
 | 
						log_debug("ffB2:       %s %s %s\n", log_id(st.ffB2, "--"), log_id(st.ffB2cemux, "--"), log_id(st.ffB2rstmux, "--"));
 | 
				
			||||||
	log_debug("ffB1:       %s %s %s\n", log_id(st.ffB1, "--"), log_id(st.ffB1cemux, "--"), log_id(st.ffB1rstmux, "--"));
 | 
						log_debug("ffB1:       %s %s %s\n", log_id(st.ffB1, "--"), log_id(st.ffB1cemux, "--"), log_id(st.ffB1rstmux, "--"));
 | 
				
			||||||
	log_debug("ffC:        %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--"));
 | 
					 | 
				
			||||||
	log_debug("ffD:        %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--"));
 | 
						log_debug("ffD:        %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--"));
 | 
				
			||||||
	log_debug("dsp:        %s\n", log_id(st.dsp, "--"));
 | 
						log_debug("dsp:        %s\n", log_id(st.dsp, "--"));
 | 
				
			||||||
	log_debug("ffM:        %s %s %s\n", log_id(st.ffM, "--"), log_id(st.ffMcemux, "--"), log_id(st.ffMrstmux, "--"));
 | 
						log_debug("ffM:        %s %s %s\n", log_id(st.ffM, "--"), log_id(st.ffMcemux, "--"), log_id(st.ffMrstmux, "--"));
 | 
				
			||||||
| 
						 | 
					@ -277,6 +275,7 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
 | 
				
			||||||
	log_debug("postAddMux: %s\n", log_id(st.postAddMux, "--"));
 | 
						log_debug("postAddMux: %s\n", log_id(st.postAddMux, "--"));
 | 
				
			||||||
	log_debug("ffP:        %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--"));
 | 
						log_debug("ffP:        %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--"));
 | 
				
			||||||
	log_debug("overflow:   %s\n", log_id(st.overflow, "--"));
 | 
						log_debug("overflow:   %s\n", log_id(st.overflow, "--"));
 | 
				
			||||||
 | 
						log_debug("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Cell *cell = st.dsp;
 | 
						Cell *cell = st.dsp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -426,12 +425,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				cell->setParam(ID(BREG), 1);
 | 
									cell->setParam(ID(BREG), 1);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (st.ffC) {
 | 
					 | 
				
			||||||
			SigSpec &C = cell->connections_.at(ID(C));
 | 
					 | 
				
			||||||
			f(C, st.ffC, st.ffCcemux, st.ffCcepol, ID(CEC), st.ffCrstmux, st.ffCrstpol, ID(RSTC));
 | 
					 | 
				
			||||||
			pm.add_siguser(C, cell);
 | 
					 | 
				
			||||||
			cell->setParam(ID(CREG), 1);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (st.ffD) {
 | 
							if (st.ffD) {
 | 
				
			||||||
			SigSpec &D = cell->connections_.at(ID(D));
 | 
								SigSpec &D = cell->connections_.at(ID(D));
 | 
				
			||||||
			f(D, st.ffD, st.ffDcemux, st.ffDcepol, ID(CED), st.ffDrstmux, st.ffDrstpol, ID(RSTD));
 | 
								f(D, st.ffD, st.ffDcemux, st.ffDcepol, ID(CED), st.ffDrstmux, st.ffDrstpol, ID(RSTD));
 | 
				
			||||||
| 
						 | 
					@ -468,9 +461,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
 | 
				
			||||||
				log(" ffB1:%s", log_id(st.ffB1));
 | 
									log(" ffB1:%s", log_id(st.ffB1));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (st.ffC)
 | 
					 | 
				
			||||||
			log(" ffC:%s", log_id(st.ffC));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (st.ffD)
 | 
							if (st.ffD)
 | 
				
			||||||
			log(" ffD:%s", log_id(st.ffD));
 | 
								log(" ffD:%s", log_id(st.ffD));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -491,6 +481,76 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
 | 
				
			||||||
	pm.blacklist(cell);
 | 
						pm.blacklist(cell);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						auto &st = pm.st_xilinx_dsp_packC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log_debug("Analysing %s.%s for Xilinx DSP packing (CREG).\n", log_id(pm.module), log_id(st.dsp));
 | 
				
			||||||
 | 
						log_debug("ffC:        %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--"));
 | 
				
			||||||
 | 
						log_debug("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Cell *cell = st.dsp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (st.clock != SigBit())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							cell->setPort(ID(CLK), st.clock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto f = [&pm,cell](SigSpec &A, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) {
 | 
				
			||||||
 | 
								SigSpec D = ff->getPort(ID(D));
 | 
				
			||||||
 | 
								SigSpec Q = pm.sigmap(ff->getPort(ID(Q)));
 | 
				
			||||||
 | 
								if (!A.empty())
 | 
				
			||||||
 | 
									A.replace(Q, D);
 | 
				
			||||||
 | 
								if (rstmux) {
 | 
				
			||||||
 | 
									SigSpec Y = rstmux->getPort(ID(Y));
 | 
				
			||||||
 | 
									SigSpec AB = rstmux->getPort(rstpol ? ID(A) : ID(B));
 | 
				
			||||||
 | 
									if (!A.empty())
 | 
				
			||||||
 | 
										A.replace(Y, AB);
 | 
				
			||||||
 | 
									if (rstport != IdString()) {
 | 
				
			||||||
 | 
										SigSpec S = rstmux->getPort(ID(S));
 | 
				
			||||||
 | 
										cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else if (rstport != IdString())
 | 
				
			||||||
 | 
									cell->setPort(rstport, State::S0);
 | 
				
			||||||
 | 
								if (cemux) {
 | 
				
			||||||
 | 
									SigSpec Y = cemux->getPort(ID(Y));
 | 
				
			||||||
 | 
									SigSpec BA = cemux->getPort(cepol ? ID(B) : ID(A));
 | 
				
			||||||
 | 
									SigSpec S = cemux->getPort(ID(S));
 | 
				
			||||||
 | 
									if (!A.empty())
 | 
				
			||||||
 | 
										A.replace(Y, BA);
 | 
				
			||||||
 | 
									cell->setPort(ceport, cepol ? S : pm.module->Not(NEW_ID, S));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									cell->setPort(ceport, State::S1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto c : Q.chunks()) {
 | 
				
			||||||
 | 
									auto it = c.wire->attributes.find(ID(init));
 | 
				
			||||||
 | 
									if (it == c.wire->attributes.end())
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									for (int i = c.offset; i < c.offset+c.width; i++) {
 | 
				
			||||||
 | 
										log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx);
 | 
				
			||||||
 | 
										it->second[i] = State::Sx;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (st.ffC) {
 | 
				
			||||||
 | 
								SigSpec &C = cell->connections_.at(ID(C));
 | 
				
			||||||
 | 
								f(C, st.ffC, st.ffCcemux, st.ffCcepol, ID(CEC), st.ffCrstmux, st.ffCrstpol, ID(RSTC));
 | 
				
			||||||
 | 
								pm.add_siguser(C, cell);
 | 
				
			||||||
 | 
								cell->setParam(ID(CREG), 1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log("  clock: %s (%s)", log_signal(st.clock), "posedge");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (st.ffC)
 | 
				
			||||||
 | 
								log(" ffC:%s", log_id(st.ffC));
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pm.blacklist(cell);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct XilinxDspPass : public Pass {
 | 
					struct XilinxDspPass : public Pass {
 | 
				
			||||||
	XilinxDspPass() : Pass("xilinx_dsp", "Xilinx: pack resources into DSPs") { }
 | 
						XilinxDspPass() : Pass("xilinx_dsp", "Xilinx: pack resources into DSPs") { }
 | 
				
			||||||
	void help() YS_OVERRIDE
 | 
						void help() YS_OVERRIDE
 | 
				
			||||||
| 
						 | 
					@ -540,16 +600,22 @@ struct XilinxDspPass : public Pass {
 | 
				
			||||||
		extra_args(args, argidx, design);
 | 
							extra_args(args, argidx, design);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto module : design->selected_modules()) {
 | 
							for (auto module : design->selected_modules()) {
 | 
				
			||||||
			pack_xilinx_simd(module, module->selected_cells());
 | 
								xilinx_simd_pack(module, module->selected_cells());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
                xilinx_dsp_pm pm(module, module->selected_cells());
 | 
					                xilinx_dsp_pm pm(module, module->selected_cells());
 | 
				
			||||||
			pm.run_xilinx_dsp_pack(pack_xilinx_dsp);
 | 
					                pm.run_xilinx_dsp_pack(xilinx_dsp_pack);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                xilinx_dsp_CREG_pm pm(module, module->selected_cells());
 | 
				
			||||||
 | 
					                pm.run_xilinx_dsp_packC(xilinx_dsp_packC);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			do {
 | 
								do {
 | 
				
			||||||
				did_something = false;
 | 
									did_something = false;
 | 
				
			||||||
				xilinx_dsp_cascade_pm pmc(module, module->selected_cells());
 | 
									xilinx_dsp_cascade_pm pm(module, module->selected_cells());
 | 
				
			||||||
				pmc.run_xilinx_dsp_cascadeP();
 | 
									pm.run_xilinx_dsp_cascadeP();
 | 
				
			||||||
				//pmc.run_xilinx_dsp_cascadeAB();
 | 
									//pm.run_xilinx_dsp_cascadeAB();
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
			} while (did_something);
 | 
								} while (did_something);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,11 +4,11 @@ udata <std::function<SigSpec(const SigSpec&)>> unextend
 | 
				
			||||||
state <SigBit> clock
 | 
					state <SigBit> clock
 | 
				
			||||||
state <SigSpec> sigA sigB sigC sigD sigM sigP
 | 
					state <SigSpec> sigA sigB sigC sigD sigM sigP
 | 
				
			||||||
state <IdString> postAddAB postAddMuxAB
 | 
					state <IdString> postAddAB postAddMuxAB
 | 
				
			||||||
state <bool> ffA1cepol ffA2cepol ffADcepol ffB1cepol ffB2cepol ffCcepol ffDcepol ffMcepol ffPcepol
 | 
					state <bool> ffA1cepol ffA2cepol ffADcepol ffB1cepol ffB2cepol ffDcepol ffMcepol ffPcepol
 | 
				
			||||||
state <bool> ffArstpol ffADrstpol ffBrstpol ffCrstpol ffDrstpol ffMrstpol ffPrstpol
 | 
					state <bool> ffArstpol ffADrstpol ffBrstpol ffDrstpol ffMrstpol ffPrstpol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
state <Cell*> ffAD ffADcemux ffADrstmux ffA1 ffA1cemux ffA1rstmux ffA2 ffA2cemux ffA2rstmux
 | 
					state <Cell*> ffAD ffADcemux ffADrstmux ffA1 ffA1cemux ffA1rstmux ffA2 ffA2cemux ffA2rstmux
 | 
				
			||||||
state <Cell*> ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux ffC ffCcemux ffCrstmux
 | 
					state <Cell*> ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux
 | 
				
			||||||
state <Cell*> ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux
 | 
					state <Cell*> ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// subpattern
 | 
					// subpattern
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,7 @@ match dsp
 | 
				
			||||||
	select dsp->type.in(\DSP48E1)
 | 
						select dsp->type.in(\DSP48E1)
 | 
				
			||||||
endmatch
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
code sigA sigB sigC sigD sigM
 | 
					code sigA sigB sigC sigD sigM clock
 | 
				
			||||||
	unextend = [](const SigSpec &sig) {
 | 
						unextend = [](const SigSpec &sig) {
 | 
				
			||||||
		int i;
 | 
							int i;
 | 
				
			||||||
		for (i = GetSize(sig)-1; i > 0; i--)
 | 
							for (i = GetSize(sig)-1; i > 0; i--)
 | 
				
			||||||
| 
						 | 
					@ -54,6 +54,8 @@ code sigA sigB sigC sigD sigM
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		sigM = P;
 | 
							sigM = P;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						clock = port(dsp, \CLK, SigBit());
 | 
				
			||||||
endcode
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock
 | 
					code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock
 | 
				
			||||||
| 
						 | 
					@ -326,26 +328,6 @@ code sigC
 | 
				
			||||||
		sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A);
 | 
							sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A);
 | 
				
			||||||
endcode
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock
 | 
					 | 
				
			||||||
	if (param(dsp, \CREG).as_int() == 0 && sigC != sigP) {
 | 
					 | 
				
			||||||
		argQ = sigC;
 | 
					 | 
				
			||||||
		subpattern(in_dffe);
 | 
					 | 
				
			||||||
		if (dff) {
 | 
					 | 
				
			||||||
			ffC = dff;
 | 
					 | 
				
			||||||
			clock = dffclock;
 | 
					 | 
				
			||||||
			if (dffrstmux) {
 | 
					 | 
				
			||||||
				ffCrstmux = dffrstmux;
 | 
					 | 
				
			||||||
				ffCrstpol = dffrstpol;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (dffcemux) {
 | 
					 | 
				
			||||||
				ffCcemux = dffcemux;
 | 
					 | 
				
			||||||
				ffCcepol = dffcepol;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			sigC = dffD;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
endcode
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
match overflow
 | 
					match overflow
 | 
				
			||||||
	if ffP
 | 
						if ffP
 | 
				
			||||||
	if param(dsp, \USE_PATTERN_DETECT, Const("NO_PATDET")).decode_string() == "NO_PATDET"
 | 
						if param(dsp, \USE_PATTERN_DETECT, Const("NO_PATDET")).decode_string() == "NO_PATDET"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										178
									
								
								passes/pmgen/xilinx_dsp_CREG.pmg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								passes/pmgen/xilinx_dsp_CREG.pmg
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,178 @@
 | 
				
			||||||
 | 
					pattern xilinx_dsp_packC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					udata <std::function<SigSpec(const SigSpec&)>> unextend
 | 
				
			||||||
 | 
					state <SigBit> clock
 | 
				
			||||||
 | 
					state <SigSpec> sigC sigP
 | 
				
			||||||
 | 
					state <bool> ffCcepol ffCrstpol
 | 
				
			||||||
 | 
					state <Cell*> ffC ffCcemux ffCrstmux
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// subpattern
 | 
				
			||||||
 | 
					state <SigSpec> argQ argD
 | 
				
			||||||
 | 
					state <bool> ffcepol ffrstpol
 | 
				
			||||||
 | 
					state <int> ffoffset
 | 
				
			||||||
 | 
					udata <SigSpec> dffD dffQ
 | 
				
			||||||
 | 
					udata <SigBit> dffclock
 | 
				
			||||||
 | 
					udata <Cell*> dff dffcemux dffrstmux
 | 
				
			||||||
 | 
					udata <bool> dffcepol dffrstpol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match dsp
 | 
				
			||||||
 | 
						select dsp->type.in(\DSP48E1)
 | 
				
			||||||
 | 
						select param(dsp, \CREG, 1).as_int() == 0
 | 
				
			||||||
 | 
						select nusers(port(dsp, \C, SigSpec())) > 1
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC sigP clock
 | 
				
			||||||
 | 
						unextend = [](const SigSpec &sig) {
 | 
				
			||||||
 | 
							int i;
 | 
				
			||||||
 | 
							for (i = GetSize(sig)-1; i > 0; i--)
 | 
				
			||||||
 | 
								if (sig[i] != sig[i-1])
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							// Do not remove non-const sign bit
 | 
				
			||||||
 | 
							if (sig[i].wire)
 | 
				
			||||||
 | 
								++i;
 | 
				
			||||||
 | 
							return sig.extract(0, i);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						sigC = unextend(port(dsp, \C, SigSpec()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec P = port(dsp, \P);
 | 
				
			||||||
 | 
						if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") {
 | 
				
			||||||
 | 
							// Only care about those bits that are used
 | 
				
			||||||
 | 
							int i;
 | 
				
			||||||
 | 
							for (i = 0; i < GetSize(P); i++) {
 | 
				
			||||||
 | 
								if (nusers(P[i]) <= 1)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								sigP.append(P[i]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							log_assert(nusers(P.extract_end(i)) <= 1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							sigP = P;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sigC == sigP)
 | 
				
			||||||
 | 
							reject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						clock = port(dsp, \CLK, SigBit());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						argQ = sigC;
 | 
				
			||||||
 | 
						subpattern(in_dffe);
 | 
				
			||||||
 | 
						if (dff) {
 | 
				
			||||||
 | 
							ffC = dff;
 | 
				
			||||||
 | 
							clock = dffclock;
 | 
				
			||||||
 | 
							if (dffrstmux) {
 | 
				
			||||||
 | 
								ffCrstmux = dffrstmux;
 | 
				
			||||||
 | 
								ffCrstpol = dffrstpol;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (dffcemux) {
 | 
				
			||||||
 | 
								ffCcemux = dffcemux;
 | 
				
			||||||
 | 
								ffCcepol = dffcepol;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sigC = dffD;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code
 | 
				
			||||||
 | 
						if (ffC)
 | 
				
			||||||
 | 
							accept;
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// #######################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					subpattern in_dffe
 | 
				
			||||||
 | 
					arg argD argQ clock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code
 | 
				
			||||||
 | 
						dff = nullptr;
 | 
				
			||||||
 | 
						for (auto c : argQ.chunks()) {
 | 
				
			||||||
 | 
							if (!c.wire)
 | 
				
			||||||
 | 
								reject;
 | 
				
			||||||
 | 
							if (c.wire->get_bool_attribute(\keep))
 | 
				
			||||||
 | 
								reject;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match ff
 | 
				
			||||||
 | 
						select ff->type.in($dff)
 | 
				
			||||||
 | 
						// DSP48E1 does not support clock inversion
 | 
				
			||||||
 | 
						select param(ff, \CLK_POLARITY).as_bool()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						slice offset GetSize(port(ff, \D))
 | 
				
			||||||
 | 
						index <SigBit> port(ff, \Q)[offset] === argQ[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check that the rest of argQ is present
 | 
				
			||||||
 | 
						filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
 | 
				
			||||||
 | 
						filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set ffoffset offset
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code argQ argD
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (clock != SigBit() && port(ff, \CLK) != clock)
 | 
				
			||||||
 | 
							reject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec Q = port(ff, \Q);
 | 
				
			||||||
 | 
						dff = ff;
 | 
				
			||||||
 | 
						dffclock = port(ff, \CLK);
 | 
				
			||||||
 | 
						dffD = argQ;
 | 
				
			||||||
 | 
						argD = port(ff, \D);
 | 
				
			||||||
 | 
						argQ = Q;
 | 
				
			||||||
 | 
						dffD.replace(argQ, argD);
 | 
				
			||||||
 | 
						// Only search for ffrstmux if dffD only
 | 
				
			||||||
 | 
						//   has two (ff, ffrstmux) users
 | 
				
			||||||
 | 
						if (nusers(dffD) > 2)
 | 
				
			||||||
 | 
							argD = SigSpec();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match ffrstmux
 | 
				
			||||||
 | 
						if !argD.empty()
 | 
				
			||||||
 | 
						select ffrstmux->type.in($mux)
 | 
				
			||||||
 | 
						index <SigSpec> port(ffrstmux, \Y) === argD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						choice <IdString> BA {\B, \A}
 | 
				
			||||||
 | 
						// DSP48E1 only supports reset to zero
 | 
				
			||||||
 | 
						select port(ffrstmux, BA).is_fully_zero()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						define <bool> pol (BA == \B)
 | 
				
			||||||
 | 
						set ffrstpol pol
 | 
				
			||||||
 | 
						semioptional
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code argD
 | 
				
			||||||
 | 
						if (ffrstmux) {
 | 
				
			||||||
 | 
							dffrstmux = ffrstmux;
 | 
				
			||||||
 | 
							dffrstpol = ffrstpol;
 | 
				
			||||||
 | 
							argD = port(ffrstmux, ffrstpol ? \A : \B);
 | 
				
			||||||
 | 
							dffD.replace(port(ffrstmux, \Y), argD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Only search for ffcemux if argQ has at
 | 
				
			||||||
 | 
							//   least 3 users (ff, <upstream>, ffrstmux) and
 | 
				
			||||||
 | 
							//   dffD only has two (ff, ffrstmux)
 | 
				
			||||||
 | 
							if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
 | 
				
			||||||
 | 
								argD = SigSpec();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							dffrstmux = nullptr;
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match ffcemux
 | 
				
			||||||
 | 
						if !argD.empty()
 | 
				
			||||||
 | 
						select ffcemux->type.in($mux)
 | 
				
			||||||
 | 
						index <SigSpec> port(ffcemux, \Y) === argD
 | 
				
			||||||
 | 
						choice <IdString> AB {\A, \B}
 | 
				
			||||||
 | 
						index <SigSpec> port(ffcemux, AB) === argQ
 | 
				
			||||||
 | 
						define <bool> pol (AB == \A)
 | 
				
			||||||
 | 
						set ffcepol pol
 | 
				
			||||||
 | 
						semioptional
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code argD
 | 
				
			||||||
 | 
						if (ffcemux) {
 | 
				
			||||||
 | 
							dffcemux = ffcemux;
 | 
				
			||||||
 | 
							dffcepol = ffcepol;
 | 
				
			||||||
 | 
							argD = port(ffcemux, ffcepol ? \B : \A);
 | 
				
			||||||
 | 
							dffD.replace(port(ffcemux, \Y), argD);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							dffcemux = nullptr;
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue