@@ -45,6 +45,7 @@ PRIVATE_NAMESPACE_BEGIN
4545#define BLACKBOX_SIM_LIB_FILE cell_sim_blackbox.v
4646#define BLACKBOX_SIM_LIB_OFAB_FILE cell_ofab_sim_blackbox.v
4747#define SIM_LIB_CARRY_FILE CARRY.v
48+ #define SIM_LIB_CARRY_BREAK_FILE CARRY_BREAK.v
4849#define LLATCHES_SIM_FILE llatches_sim.v
4950#define DSP_SIM_LIB_FILE dsp_sim.v
5051#define BRAMS_SIM_LIB_FILE brams_sim.v
@@ -5839,6 +5840,111 @@ static void show_sig(const RTLIL::SigSpec &sig)
58395840 }
58405841 }
58415842
5843+ // We replace CARRY cells by CARRY_BREAK cells when we encounter carry chains
5844+ // longer than 'max_carry_length'
5845+ //
5846+ // Return 1 if at least one break occured, 0 otherwise.
5847+ //
5848+ int insert_carry_chain_break_cells ()
5849+ {
5850+ int break_chain = 0 ;
5851+
5852+ dict<RTLIL::SigSpec, Cell *> ci2cell;
5853+ dict<Cell *, RTLIL::SigSpec> co2cell;
5854+ std::map<int , std::vector<Cell *>> carry_chains;
5855+ vector<Cell *> carry_chain_head_cells;
5856+
5857+ for (auto cell : _design->top_module ()->cells ())
5858+ {
5859+ if (cell->type != RTLIL::escape_id (" CARRY" ))
5860+ continue ;
5861+
5862+ // log("Cout = %s, CIN = %s\n",log_signal(cell->getPort(RTLIL::escape_id("COUT"))),log_signal(cell->getPort(RTLIL::escape_id("CIN"))));
5863+ bool noCo = true ;
5864+ for (auto &conn : cell->connections ())
5865+ {
5866+ IdString portName = conn.first ;
5867+ RTLIL::SigSpec actual = conn.second ;
5868+
5869+ if (portName == RTLIL::escape_id (" CIN" ))
5870+ {
5871+ ci2cell[actual] = cell;
5872+ continue ;
5873+ }
5874+
5875+ if (portName == RTLIL::escape_id (" COUT" ) && !(actual.empty ()))
5876+ {
5877+ noCo = false ;
5878+ co2cell[cell] = actual;
5879+ continue ;
5880+ }
5881+ }
5882+ if (noCo)
5883+ {
5884+ co2cell[cell] = {};
5885+ carry_chain_head_cells.push_back (cell);
5886+ }
5887+ }
5888+ vector<RTLIL::SigSpec> carry_chain_head_co2cell;
5889+
5890+ int chain = 0 ;
5891+ for (auto head_cell : carry_chain_head_cells)
5892+ {
5893+ RTLIL::SigSpec signal = head_cell->getPort (RTLIL::escape_id (" CIN" ));
5894+ chain += 1 ;
5895+ carry_chains[chain].push_back (head_cell);
5896+ while (!signal.empty ())
5897+ {
5898+ bool found = false ;
5899+ for (auto &co_signal : co2cell)
5900+ {
5901+ if (co_signal.second == signal)
5902+ {
5903+ carry_chains[chain].push_back (co_signal.first );
5904+ signal = co_signal.first ->getPort (RTLIL::escape_id (" CIN" ));
5905+ found = true ;
5906+ break ;
5907+ }
5908+ }
5909+ if (!found)
5910+ {
5911+ break ;
5912+ }
5913+ }
5914+ }
5915+
5916+ for (auto &chain : carry_chains)
5917+ {
5918+ std::vector<Cell*> original_chain = chain.second ;
5919+
5920+ int start = max_carry_length;
5921+ int step = max_carry_length-2 ;
5922+
5923+ for (long unsigned int i = start; (i > 0 ) && (i < original_chain.size ()); i += step) {
5924+
5925+ Cell* previous_cell = original_chain[i-1 ];
5926+ Cell* cell = original_chain[i];
5927+
5928+ if (previous_cell->type != RTLIL::escape_id (" CARRY" )) {
5929+ continue ; // should never happen as cells are always CARRY
5930+ }
5931+ if (cell->type != RTLIL::escape_id (" CARRY" )) {
5932+ continue ; // should never happen as cells are always CARRY
5933+ }
5934+
5935+ // Every max length on the chain replace CARRY cell by a
5936+ // CARRY_BREAK cell.
5937+ //
5938+ previous_cell->type = RTLIL::escape_id (" CARRY_BREAK" );
5939+ log (" NOTE: Breaking carry chain at carry cell '%s'\n " ,
5940+ (previous_cell->name ).c_str ());
5941+ break_chain = 1 ;
5942+ }
5943+ }
5944+
5945+ return break_chain;
5946+ }
5947+
58425948 // Force 'keep' attribute on original IO BUF cells instantiated at RTL.
58435949 // (ex: EDA-3307 where one I_BUF is removed by optimizer because input is not used)
58445950 //
@@ -8449,6 +8555,42 @@ void collect_clocks (RTLIL::Module* module,
84498555 log_warning (" DSP exceeds the available DSP block limit (%d) on the device; the excess %d DSP blocks will be mapped to LUTs.\n " ,max_dsp, remaining_sum);
84508556 }
84518557 }
8558+
8559+ // We try to break long carry chains that exceed 'max_carry_length'
8560+ //
8561+ // 0. Extract all carry chains (use 'reportCarryChains' source code)
8562+ // 1. replace CARRY cells by CARRY_BREAK cells every max_carry_length-2
8563+ // 2. techmap CARRY_BREAK cells and replace them by verilog model
8564+ // 3. clean up design after techmap
8565+ //
8566+ void break_carry_chains ()
8567+ {
8568+ // Performs 0. and 1.
8569+ //
8570+ int carry_breaks = insert_carry_chain_break_cells ();
8571+
8572+ if (!carry_breaks) {
8573+ return ;
8574+ }
8575+
8576+ log (" NOTE: after inserting carry chain break cells" );
8577+ run (" stat" );
8578+
8579+ // Perform 2.
8580+
8581+ // string rreadArgs = GET_FILE_PATH(GENESIS_3_DIR, carry_break.v);
8582+ string rreadArgs = GET_FILE_PATH_RS_FPGA_SIM (GENESIS_3_DIR, SIM_LIB_CARRY_BREAK_FILE);
8583+
8584+ // tech map the carry_break cells
8585+ //
8586+ run (stringf (" techmap -map %s " , rreadArgs.c_str ()));
8587+
8588+ // Perform 3.
8589+ //
8590+ run (" opt_clean -purge" );
8591+
8592+ log (" NOTE: after carry chain breaks" );
8593+ }
84528594
84538595 void script () override
84548596 {
@@ -8984,8 +9126,13 @@ void collect_clocks (RTLIL::Module* module,
89849126 break ;
89859127 }
89869128 }
9129+
9130+ // We try to break long carry chains that exceed 'max_carry_length'
9131+ //
9132+ break_carry_chains ();
9133+
89879134 run (" stat" );
8988- break ;
9135+ break ;
89899136 }
89909137 case Technologies::GENERIC: {
89919138 run (" techmap" );
0 commit comments