mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	Merge branch 'xaig' of github.com:YosysHQ/yosys into xaig
This commit is contained in:
		
						commit
						4df4a97ffa
					
				
					 8 changed files with 382 additions and 41 deletions
				
			
		| 
						 | 
				
			
			@ -16,6 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev
 | 
			
		|||
    - Added "gate2lut.v" techmap rule
 | 
			
		||||
    - Added "rename -src"
 | 
			
		||||
    - Added "equiv_opt" pass
 | 
			
		||||
    - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Yosys 0.7 .. Yosys 0.8
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,9 @@ PRIVATE_NAMESPACE_BEGIN
 | 
			
		|||
struct ShregmapTech
 | 
			
		||||
{
 | 
			
		||||
	virtual ~ShregmapTech() { }
 | 
			
		||||
	virtual bool analyze(vector<int> &taps) = 0;
 | 
			
		||||
	virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {}
 | 
			
		||||
	virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {}
 | 
			
		||||
	virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) = 0;
 | 
			
		||||
	virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +56,7 @@ struct ShregmapOptions
 | 
			
		|||
 | 
			
		||||
struct ShregmapTechGreenpak4 : ShregmapTech
 | 
			
		||||
{
 | 
			
		||||
	bool analyze(vector<int> &taps)
 | 
			
		||||
	bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/)
 | 
			
		||||
	{
 | 
			
		||||
		if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
 | 
			
		||||
			taps.clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -91,6 +93,145 @@ struct ShregmapTechGreenpak4 : ShregmapTech
 | 
			
		|||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ShregmapTechXilinx7 : ShregmapTech
 | 
			
		||||
{
 | 
			
		||||
	dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset;
 | 
			
		||||
	const ShregmapOptions &opts;
 | 
			
		||||
 | 
			
		||||
	ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {}
 | 
			
		||||
 | 
			
		||||
	virtual void init(const Module* module, const SigMap &sigmap) override
 | 
			
		||||
	{
 | 
			
		||||
		for (const auto &i : module->cells_) {
 | 
			
		||||
			auto cell = i.second;
 | 
			
		||||
			if (cell->type == "$shiftx") {
 | 
			
		||||
				if (cell->getParam("\\Y_WIDTH") != 1) continue;
 | 
			
		||||
				int j = 0;
 | 
			
		||||
				for (auto bit : sigmap(cell->getPort("\\A")))
 | 
			
		||||
					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
 | 
			
		||||
				log_assert(j == cell->getParam("\\A_WIDTH").as_int());
 | 
			
		||||
			}
 | 
			
		||||
			else if (cell->type == "$mux") {
 | 
			
		||||
				int j = 0;
 | 
			
		||||
				for (auto bit : sigmap(cell->getPort("\\A")))
 | 
			
		||||
					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
 | 
			
		||||
				j = 0;
 | 
			
		||||
				for (auto bit : sigmap(cell->getPort("\\B")))
 | 
			
		||||
					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override
 | 
			
		||||
	{
 | 
			
		||||
		auto it = sigbit_to_shiftx_offset.find(bit);
 | 
			
		||||
		if (it == sigbit_to_shiftx_offset.end())
 | 
			
		||||
			return;
 | 
			
		||||
		if (cell) {
 | 
			
		||||
			if (cell->type == "$shiftx" && port == "\\A")
 | 
			
		||||
				return;
 | 
			
		||||
			if (cell->type == "$mux" && (port == "\\A" || port == "\\B"))
 | 
			
		||||
				return;
 | 
			
		||||
		}
 | 
			
		||||
		sigbit_to_shiftx_offset.erase(it);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) override
 | 
			
		||||
	{
 | 
			
		||||
		if (GetSize(taps) == 1)
 | 
			
		||||
			return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]);
 | 
			
		||||
 | 
			
		||||
		if (taps.back() < opts.minlen-1)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		Cell *shiftx = nullptr;
 | 
			
		||||
		int group = 0;
 | 
			
		||||
		for (int i = 0; i < GetSize(taps); ++i) {
 | 
			
		||||
			auto it = sigbit_to_shiftx_offset.find(qbits[i]);
 | 
			
		||||
			if (it == sigbit_to_shiftx_offset.end())
 | 
			
		||||
				return false;
 | 
			
		||||
 | 
			
		||||
			// Check taps are sequential
 | 
			
		||||
			if (i != taps[i])
 | 
			
		||||
				return false;
 | 
			
		||||
			// Check taps are not connected to a shift register,
 | 
			
		||||
			// or sequential to the same shift register
 | 
			
		||||
			if (i == 0) {
 | 
			
		||||
				int offset;
 | 
			
		||||
				std::tie(shiftx,offset,group) = it->second;
 | 
			
		||||
				if (offset != i)
 | 
			
		||||
					return false;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				Cell *shiftx_ = std::get<0>(it->second);
 | 
			
		||||
				if (shiftx_ != shiftx)
 | 
			
		||||
					return false;
 | 
			
		||||
				int offset = std::get<1>(it->second);
 | 
			
		||||
				if (offset != i)
 | 
			
		||||
					return false;
 | 
			
		||||
				int group_ = std::get<2>(it->second);
 | 
			
		||||
				if (group_ != group)
 | 
			
		||||
					return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		log_assert(shiftx);
 | 
			
		||||
 | 
			
		||||
		// Only map if $shiftx exclusively covers the shift register
 | 
			
		||||
		if (shiftx->type == "$shiftx") {
 | 
			
		||||
			if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int())
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
		else if (shiftx->type == "$mux") {
 | 
			
		||||
			if (GetSize(taps) != 2)
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
		else log_abort();
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) override
 | 
			
		||||
	{
 | 
			
		||||
		const auto &tap = *taps.begin();
 | 
			
		||||
		auto bit = tap.second;
 | 
			
		||||
 | 
			
		||||
		auto it = sigbit_to_shiftx_offset.find(bit);
 | 
			
		||||
		log_assert(it != sigbit_to_shiftx_offset.end());
 | 
			
		||||
 | 
			
		||||
		auto newcell = cell->module->addCell(NEW_ID, "$__XILINX_SHREG_");
 | 
			
		||||
		newcell->set_src_attribute(cell->get_src_attribute());
 | 
			
		||||
		newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH"));
 | 
			
		||||
		newcell->setParam("\\INIT", cell->getParam("\\INIT"));
 | 
			
		||||
		newcell->setParam("\\CLKPOL", cell->getParam("\\CLKPOL"));
 | 
			
		||||
		newcell->setParam("\\ENPOL", cell->getParam("\\ENPOL"));
 | 
			
		||||
 | 
			
		||||
		newcell->setPort("\\C", cell->getPort("\\C"));
 | 
			
		||||
		newcell->setPort("\\D", cell->getPort("\\D"));
 | 
			
		||||
		if (cell->hasPort("\\E"))
 | 
			
		||||
			newcell->setPort("\\E", cell->getPort("\\E"));
 | 
			
		||||
 | 
			
		||||
		Cell* shiftx = std::get<0>(it->second);
 | 
			
		||||
		RTLIL::SigSpec l_wire, q_wire;
 | 
			
		||||
		if (shiftx->type == "$shiftx") {
 | 
			
		||||
			l_wire = shiftx->getPort("\\B");
 | 
			
		||||
			q_wire = shiftx->getPort("\\Y");
 | 
			
		||||
			shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
 | 
			
		||||
		}
 | 
			
		||||
		else if (shiftx->type == "$mux") {
 | 
			
		||||
			l_wire = shiftx->getPort("\\S");
 | 
			
		||||
			q_wire = shiftx->getPort("\\Y");
 | 
			
		||||
			shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
 | 
			
		||||
		}
 | 
			
		||||
		else log_abort();
 | 
			
		||||
 | 
			
		||||
		newcell->setPort("\\Q", q_wire);
 | 
			
		||||
		newcell->setPort("\\L", l_wire);
 | 
			
		||||
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct ShregmapWorker
 | 
			
		||||
{
 | 
			
		||||
	Module *module;
 | 
			
		||||
| 
						 | 
				
			
			@ -113,8 +254,10 @@ struct ShregmapWorker
 | 
			
		|||
		for (auto wire : module->wires())
 | 
			
		||||
		{
 | 
			
		||||
			if (wire->port_output || wire->get_bool_attribute("\\keep")) {
 | 
			
		||||
				for (auto bit : sigmap(wire))
 | 
			
		||||
				for (auto bit : sigmap(wire)) {
 | 
			
		||||
					sigbit_with_non_chain_users.insert(bit);
 | 
			
		||||
					if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {});
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (wire->attributes.count("\\init")) {
 | 
			
		||||
| 
						 | 
				
			
			@ -152,8 +295,10 @@ struct ShregmapWorker
 | 
			
		|||
 | 
			
		||||
			for (auto conn : cell->connections())
 | 
			
		||||
				if (cell->input(conn.first))
 | 
			
		||||
					for (auto bit : sigmap(conn.second))
 | 
			
		||||
					for (auto bit : sigmap(conn.second)) {
 | 
			
		||||
						sigbit_with_non_chain_users.insert(bit);
 | 
			
		||||
						if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first);
 | 
			
		||||
					}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -258,7 +403,7 @@ struct ShregmapWorker
 | 
			
		|||
					if (taps.empty() || taps.back() < depth-1)
 | 
			
		||||
						taps.push_back(depth-1);
 | 
			
		||||
 | 
			
		||||
					if (opts.tech->analyze(taps))
 | 
			
		||||
					if (opts.tech->analyze(taps, qbits))
 | 
			
		||||
						break;
 | 
			
		||||
 | 
			
		||||
					taps.pop_back();
 | 
			
		||||
| 
						 | 
				
			
			@ -377,6 +522,9 @@ struct ShregmapWorker
 | 
			
		|||
	ShregmapWorker(Module *module, const ShregmapOptions &opts) :
 | 
			
		||||
			module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
 | 
			
		||||
	{
 | 
			
		||||
		if (opts.tech)
 | 
			
		||||
			opts.tech->init(module, sigmap);
 | 
			
		||||
 | 
			
		||||
		make_sigbit_chain_next_prev();
 | 
			
		||||
		find_chain_start_cells();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -501,6 +649,12 @@ struct ShregmapPass : public Pass {
 | 
			
		|||
					clkpol = "pos";
 | 
			
		||||
					opts.zinit = true;
 | 
			
		||||
					opts.tech = new ShregmapTechGreenpak4;
 | 
			
		||||
				}
 | 
			
		||||
				else if (tech == "xilinx") {
 | 
			
		||||
					opts.init = true;
 | 
			
		||||
					opts.params = true;
 | 
			
		||||
					enpol = "any_or_none";
 | 
			
		||||
					opts.tech = new ShregmapTechXilinx7(opts);
 | 
			
		||||
				} else {
 | 
			
		||||
					argidx--;
 | 
			
		||||
					break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,4 +17,130 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// Empty for now
 | 
			
		||||
module \$__SHREG_ (input C, input D, input E, output Q);
 | 
			
		||||
  parameter DEPTH = 0;
 | 
			
		||||
  parameter [DEPTH-1:0] INIT = 0;
 | 
			
		||||
  parameter CLKPOL = 1;
 | 
			
		||||
  parameter ENPOL = 2;
 | 
			
		||||
 | 
			
		||||
  \$__XILINX_SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(DEPTH-1), .E(E), .Q(Q));
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO);
 | 
			
		||||
  parameter DEPTH = 0;
 | 
			
		||||
  parameter [DEPTH-1:0] INIT = 0;
 | 
			
		||||
  parameter CLKPOL = 1;
 | 
			
		||||
  parameter ENPOL = 2;
 | 
			
		||||
 | 
			
		||||
  // shregmap's INIT parameter shifts out LSB first;
 | 
			
		||||
  // however Xilinx expects MSB first
 | 
			
		||||
  function [DEPTH-1:0] brev;
 | 
			
		||||
    input [DEPTH-1:0] din;
 | 
			
		||||
    integer i;
 | 
			
		||||
    begin
 | 
			
		||||
      for (i = 0; i < DEPTH; i=i+1)
 | 
			
		||||
        brev[i] = din[DEPTH-1-i];
 | 
			
		||||
    end
 | 
			
		||||
  endfunction
 | 
			
		||||
  localparam [DEPTH-1:0] INIT_R = brev(INIT);
 | 
			
		||||
 | 
			
		||||
  parameter _TECHMAP_CONSTMSK_L_ = 0;
 | 
			
		||||
  parameter _TECHMAP_CONSTVAL_L_ = 0;
 | 
			
		||||
 | 
			
		||||
  wire CE;
 | 
			
		||||
  generate
 | 
			
		||||
    if (ENPOL == 0)
 | 
			
		||||
      assign CE = ~E;
 | 
			
		||||
    else if (ENPOL == 1)
 | 
			
		||||
      assign CE = E;
 | 
			
		||||
    else
 | 
			
		||||
      assign CE = 1'b1;
 | 
			
		||||
    if (DEPTH == 1) begin
 | 
			
		||||
      if (CLKPOL)
 | 
			
		||||
          FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0));
 | 
			
		||||
      else
 | 
			
		||||
          FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0));
 | 
			
		||||
    end else
 | 
			
		||||
    if (DEPTH <= 16) begin
 | 
			
		||||
      SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(L[0]), .A1(L[1]), .A2(L[2]), .A3(L[3]), .CE(CE), .CLK(C), .D(D), .Q(Q));
 | 
			
		||||
    end else
 | 
			
		||||
    if (DEPTH > 17 && DEPTH <= 32) begin
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(Q));
 | 
			
		||||
    end else
 | 
			
		||||
    if (DEPTH > 33 && DEPTH <= 64) begin
 | 
			
		||||
      wire T0, T1, T2;
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
 | 
			
		||||
      \$__XILINX_SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L), .E(E), .Q(T2));
 | 
			
		||||
      if (&_TECHMAP_CONSTMSK_L_)
 | 
			
		||||
        assign Q = T2;
 | 
			
		||||
      else
 | 
			
		||||
        MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(L[5]));
 | 
			
		||||
    end else
 | 
			
		||||
    if (DEPTH > 65 && DEPTH <= 96) begin
 | 
			
		||||
      wire T0, T1, T2, T3, T4, T5, T6;
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
 | 
			
		||||
      \$__XILINX_SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4));
 | 
			
		||||
      if (&_TECHMAP_CONSTMSK_L_)
 | 
			
		||||
        assign Q = T4;
 | 
			
		||||
      else begin
 | 
			
		||||
        MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5]));
 | 
			
		||||
        MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(L[5]));
 | 
			
		||||
        MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(L[6]));
 | 
			
		||||
      end
 | 
			
		||||
    end else
 | 
			
		||||
    if (DEPTH > 97 && DEPTH < 128) begin
 | 
			
		||||
      wire T0, T1, T2, T3, T4, T5, T6, T7, T8;
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
 | 
			
		||||
      \$__XILINX_SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6));
 | 
			
		||||
      if (&_TECHMAP_CONSTMSK_L_)
 | 
			
		||||
        assign Q = T6;
 | 
			
		||||
      else begin
 | 
			
		||||
        MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5]));
 | 
			
		||||
        MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5]));
 | 
			
		||||
        MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6]));
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
    else if (DEPTH == 128) begin
 | 
			
		||||
      wire T0, T1, T2, T3, T4, T5, T6;
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
 | 
			
		||||
      SRLC32E #(.INIT(INIT_R[128-1:96]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_3 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T5), .Q(T6), .Q31(SO));
 | 
			
		||||
      if (&_TECHMAP_CONSTMSK_L_)
 | 
			
		||||
        assign Q = T6;
 | 
			
		||||
      else begin
 | 
			
		||||
        wire T7, T8;
 | 
			
		||||
        MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5]));
 | 
			
		||||
        MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5]));
 | 
			
		||||
        MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6]));
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
    else if (DEPTH <= 129 && ~&_TECHMAP_CONSTMSK_L_) begin
 | 
			
		||||
      // Handle cases where fixed-length depth is
 | 
			
		||||
      // just 1 over a convenient value
 | 
			
		||||
      \$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q));
 | 
			
		||||
    end
 | 
			
		||||
    else begin
 | 
			
		||||
      localparam lower_clog2 = $clog2((DEPTH+1)/2);
 | 
			
		||||
      localparam lower_depth = 2 ** lower_clog2;
 | 
			
		||||
      wire T0, T1, T2, T3;
 | 
			
		||||
      if (&_TECHMAP_CONSTMSK_L_) begin
 | 
			
		||||
        \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(lower_depth-1), .E(E), .Q(T0));
 | 
			
		||||
        \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(DEPTH-lower_depth-1), .E(E), .Q(Q), .SO(T3));
 | 
			
		||||
      end
 | 
			
		||||
      else begin
 | 
			
		||||
        \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1));
 | 
			
		||||
        \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3));
 | 
			
		||||
        assign Q = L[lower_clog2] ? T2 : T0;
 | 
			
		||||
      end
 | 
			
		||||
      if (DEPTH == 2 * lower_depth)
 | 
			
		||||
          assign SO = T3;
 | 
			
		||||
    end
 | 
			
		||||
  endgenerate
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
`ifndef SRL_ONLY
 | 
			
		||||
`endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -308,3 +308,42 @@ module RAM128X1D (
 | 
			
		|||
  wire clk = WCLK ^ IS_WCLK_INVERTED;
 | 
			
		||||
  always @(posedge clk) if (WE) mem[A] <= D;
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module SRL16E (
 | 
			
		||||
  output Q,
 | 
			
		||||
  input A0, A1, A2, A3, CE, CLK, D
 | 
			
		||||
);
 | 
			
		||||
  parameter [15:0] INIT = 16'h0000;
 | 
			
		||||
  parameter [0:0] IS_CLK_INVERTED = 1'b0;
 | 
			
		||||
 | 
			
		||||
  reg [15:0] r = INIT;
 | 
			
		||||
  assign Q = r[{A3,A2,A1,A0}];
 | 
			
		||||
  generate
 | 
			
		||||
    if (IS_CLK_INVERTED) begin
 | 
			
		||||
      always @(negedge CLK) if (CE) r <= { r[14:0], D };
 | 
			
		||||
    end
 | 
			
		||||
    else
 | 
			
		||||
        always @(posedge CLK) if (CE) r <= { r[14:0], D };
 | 
			
		||||
  endgenerate
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module SRLC32E (
 | 
			
		||||
  output Q,
 | 
			
		||||
  output Q31,
 | 
			
		||||
  input [4:0] A,
 | 
			
		||||
  input CE, CLK, D
 | 
			
		||||
);
 | 
			
		||||
  parameter [31:0] INIT = 32'h00000000;
 | 
			
		||||
  parameter [0:0] IS_CLK_INVERTED = 1'b0;
 | 
			
		||||
 | 
			
		||||
  reg [31:0] r = INIT;
 | 
			
		||||
  assign Q31 = r[31];
 | 
			
		||||
  assign Q = r[A];
 | 
			
		||||
  generate
 | 
			
		||||
    if (IS_CLK_INVERTED) begin
 | 
			
		||||
      always @(negedge CLK) if (CE) r <= { r[30:0], D };
 | 
			
		||||
    end
 | 
			
		||||
    else
 | 
			
		||||
      always @(posedge CLK) if (CE) r <= { r[30:0], D };
 | 
			
		||||
  endgenerate
 | 
			
		||||
endmodule
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -135,8 +135,8 @@ function xtract_cell_decl()
 | 
			
		|||
	xtract_cell_decl ROM256X1
 | 
			
		||||
	xtract_cell_decl ROM32X1
 | 
			
		||||
	xtract_cell_decl ROM64X1
 | 
			
		||||
	xtract_cell_decl SRL16E
 | 
			
		||||
	xtract_cell_decl SRLC32E
 | 
			
		||||
	#xtract_cell_decl SRL16E
 | 
			
		||||
	#xtract_cell_decl SRLC32E
 | 
			
		||||
	xtract_cell_decl STARTUPE2 "(* keep *)"
 | 
			
		||||
	xtract_cell_decl USR_ACCESSE2
 | 
			
		||||
	xtract_cell_decl XADC
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3809,22 +3809,6 @@ module ROM64X1 (...);
 | 
			
		|||
    input A0, A1, A2, A3, A4, A5;
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module SRL16E (...);
 | 
			
		||||
    parameter [15:0] INIT = 16'h0000;
 | 
			
		||||
    parameter [0:0] IS_CLK_INVERTED = 1'b0;
 | 
			
		||||
    output Q;
 | 
			
		||||
    input A0, A1, A2, A3, CE, CLK, D;
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module SRLC32E (...);
 | 
			
		||||
    parameter [31:0] INIT = 32'h00000000;
 | 
			
		||||
    parameter [0:0] IS_CLK_INVERTED = 1'b0;
 | 
			
		||||
    output Q;
 | 
			
		||||
    output Q31;
 | 
			
		||||
    input [4:0] A;
 | 
			
		||||
    input CE, CLK, D;
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
(* keep *)
 | 
			
		||||
module STARTUPE2 (...);
 | 
			
		||||
    parameter PROG_USR = "FALSE";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,21 +22,26 @@
 | 
			
		|||
 | 
			
		||||
`ifndef _NO_FFS
 | 
			
		||||
 | 
			
		||||
`ifndef _NO_POS_SR
 | 
			
		||||
module  \$_DFF_N_   (input D, C, output Q);    FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
 | 
			
		||||
module  \$_DFF_P_   (input D, C, output Q);    FDRE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
 | 
			
		||||
 | 
			
		||||
module  \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E),    .R(1'b0)); endmodule
 | 
			
		||||
module  \$_DFFE_PP_ (input D, C, E, output Q); FDRE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E),    .R(1'b0)); endmodule
 | 
			
		||||
 | 
			
		||||
module  \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_         _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule
 | 
			
		||||
module  \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
 | 
			
		||||
module  \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_         _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule
 | 
			
		||||
module  \$_DFF_PP0_ (input D, C, R, output Q); FDCE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
 | 
			
		||||
 | 
			
		||||
module  \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1          _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule
 | 
			
		||||
module  \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
 | 
			
		||||
module  \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1          _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule
 | 
			
		||||
module  \$_DFF_PP1_ (input D, C, R, output Q); FDPE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
 | 
			
		||||
`endif
 | 
			
		||||
 | 
			
		||||
module  \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_         _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule
 | 
			
		||||
module  \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_         _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule
 | 
			
		||||
 | 
			
		||||
module  \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1          _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule
 | 
			
		||||
module  \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1          _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule
 | 
			
		||||
`endif
 | 
			
		||||
 | 
			
		||||
`endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,10 +64,13 @@ struct SynthXilinxPass : public Pass
 | 
			
		|||
		log("        (this feature is experimental and incomplete)\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -nobram\n");
 | 
			
		||||
		log("        disable infering of block rams\n");
 | 
			
		||||
		log("        disable inference of block rams\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -nodram\n");
 | 
			
		||||
		log("        disable infering of distributed rams\n");
 | 
			
		||||
		log("        disable inference of distributed rams\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -nosrl\n");
 | 
			
		||||
		log("        disable inference of shift registers\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    -run <from_label>:<to_label>\n");
 | 
			
		||||
		log("        only run the commands between the labels (see below). an empty\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -108,23 +111,28 @@ struct SynthXilinxPass : public Pass
 | 
			
		|||
		log("        techmap -map +/xilinx/drams_map.v\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    fine:\n");
 | 
			
		||||
		log("        opt -fast -full\n");
 | 
			
		||||
		log("        opt -fast\n");
 | 
			
		||||
		log("        memory_map\n");
 | 
			
		||||
		log("        dffsr2dff\n");
 | 
			
		||||
		log("        dff2dffe\n");
 | 
			
		||||
		log("        opt -full\n");
 | 
			
		||||
		log("        techmap -map +/techmap.v -map +/xilinx/arith_map.v\n");
 | 
			
		||||
		log("        techmap -map +/xilinx/arith_map.v\n");
 | 
			
		||||
		log("        opt -fast\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    map_cells:\n");
 | 
			
		||||
		log("        simplemap t:$dff t:$dffe (without '-nosrl' only)\n");
 | 
			
		||||
		log("        pmux2shiftx (without '-nosrl' only)\n");
 | 
			
		||||
		log("        opt_expr -mux_undef (without '-nosrl' only)\n");
 | 
			
		||||
		log("        shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n");
 | 
			
		||||
		log("        techmap -map +/xilinx/cells_map.v\n");
 | 
			
		||||
		log("        clean\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    map_luts:\n");
 | 
			
		||||
		log("        techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?\n");
 | 
			
		||||
		log("        opt -full\n");
 | 
			
		||||
		log("        techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\n");
 | 
			
		||||
		log("        abc -luts 2:2,3,6:5,10,20 [-dff]\n");
 | 
			
		||||
		log("        clean\n");
 | 
			
		||||
		log("        techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v");
 | 
			
		||||
		log("        shregmap -minlen 3 -init -params -enpol any_or_none (without '-nosrl' only)\n");
 | 
			
		||||
		log("        techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
 | 
			
		||||
		log("        dffinit -ff FDRE   Q INIT -ff FDCE   Q INIT -ff FDPE   Q INIT -ff FDSE   Q INIT \\\n");
 | 
			
		||||
		log("                -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n");
 | 
			
		||||
		log("        clean\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +161,7 @@ struct SynthXilinxPass : public Pass
 | 
			
		|||
		bool vpr = false;
 | 
			
		||||
		bool nobram = false;
 | 
			
		||||
		bool nodram = false;
 | 
			
		||||
		bool nosrl = false;
 | 
			
		||||
 | 
			
		||||
		size_t argidx;
 | 
			
		||||
		for (argidx = 1; argidx < args.size(); argidx++)
 | 
			
		||||
| 
						 | 
				
			
			@ -196,6 +205,10 @@ struct SynthXilinxPass : public Pass
 | 
			
		|||
			if (args[argidx] == "-nodram") {
 | 
			
		||||
				nodram = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (args[argidx] == "-nosrl") {
 | 
			
		||||
				nosrl = true;
 | 
			
		||||
				continue;
 | 
			
		||||
            }
 | 
			
		||||
			if (args[argidx] == "-abc9") {
 | 
			
		||||
				abc = "abc9";
 | 
			
		||||
| 
						 | 
				
			
			@ -259,16 +272,15 @@ struct SynthXilinxPass : public Pass
 | 
			
		|||
 | 
			
		||||
		if (check_label(active, run_from, run_to, "fine"))
 | 
			
		||||
		{
 | 
			
		||||
			Pass::call(design, "opt -fast -full");
 | 
			
		||||
			Pass::call(design, "opt -fast");
 | 
			
		||||
			Pass::call(design, "memory_map");
 | 
			
		||||
			Pass::call(design, "dffsr2dff");
 | 
			
		||||
			Pass::call(design, "dff2dffe");
 | 
			
		||||
			Pass::call(design, "opt -full");
 | 
			
		||||
 | 
			
		||||
			if (vpr) {
 | 
			
		||||
				Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
 | 
			
		||||
				Pass::call(design, "techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
 | 
			
		||||
			} else {
 | 
			
		||||
				Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v");
 | 
			
		||||
				Pass::call(design, "techmap -map +/xilinx/arith_map.v");
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Pass::call(design, "hierarchy -check");
 | 
			
		||||
| 
						 | 
				
			
			@ -277,16 +289,36 @@ struct SynthXilinxPass : public Pass
 | 
			
		|||
 | 
			
		||||
		if (check_label(active, run_from, run_to, "map_cells"))
 | 
			
		||||
		{
 | 
			
		||||
			if (!nosrl) {
 | 
			
		||||
				// shregmap operates on bit-level flops, not word-level,
 | 
			
		||||
				//   so break those down here
 | 
			
		||||
				Pass::call(design, "simplemap t:$dff t:$dffe");
 | 
			
		||||
				// shregmap -tech xilinx can cope with $shiftx and $mux
 | 
			
		||||
				//   cells for identifiying variable-length shift registers,
 | 
			
		||||
				//   so attempt to convert $pmux-es to the former
 | 
			
		||||
				Pass::call(design, "pmux2shiftx");
 | 
			
		||||
				// pmux2shiftx can leave behind a $pmux with a single entry
 | 
			
		||||
				//   -- need this to clean that up before shregmap
 | 
			
		||||
				Pass::call(design, "opt_expr -mux_undef");
 | 
			
		||||
				// shregmap with '-tech xilinx' infers variable length shift regs
 | 
			
		||||
				Pass::call(design, "shregmap -tech xilinx -minlen 3");
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Pass::call(design, "techmap -map +/xilinx/cells_map.v");
 | 
			
		||||
			Pass::call(design, "clean");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (check_label(active, run_from, run_to, "map_luts"))
 | 
			
		||||
		{
 | 
			
		||||
			Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?");
 | 
			
		||||
			Pass::call(design, "opt -full");
 | 
			
		||||
			Pass::call(design, "techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v");
 | 
			
		||||
			Pass::call(design, abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
 | 
			
		||||
			Pass::call(design, "clean");
 | 
			
		||||
			Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v");
 | 
			
		||||
			// This shregmap call infers fixed length shift registers after abc
 | 
			
		||||
			//   has performed any necessary retiming
 | 
			
		||||
			if (!nosrl)
 | 
			
		||||
				Pass::call(design, "shregmap -minlen 3 -init -params -enpol any_or_none");
 | 
			
		||||
			Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
 | 
			
		||||
			Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
 | 
			
		||||
					"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
 | 
			
		||||
			Pass::call(design, "clean");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue