Merge remote-tracking branch 'origin/eddie/abc9_refactor' into eddie/abc9_required
authorEddie Hung <eddie@fpgeh.com>
Tue, 14 Jan 2020 20:57:56 +0000 (12:57 -0800)
committerEddie Hung <eddie@fpgeh.com>
Tue, 14 Jan 2020 20:57:56 +0000 (12:57 -0800)
1  2 
backends/aiger/xaiger.cc
passes/techmap/abc9.cc
passes/techmap/abc9_ops.cc

index d934a9aa969b4dcde455f4e4a651173d907e86ae,f9890a59210ae495d56801d6babc12a8e578310c..d3415e45d1d454dddf9476cc7b8988a2faaa00a0
@@@ -184,88 -184,77 +184,95 @@@ struct XAigerWrite
                                }
                        }
  
-               std::vector<int> arrivals;
 -              dict<IdString,dict<IdString,int>> arrival_cache;
++              dict<IdString,dict<IdString,std::vector<int>>> arrivals_cache;
                for (auto cell : module->cells()) {
-                       if (cell->type == "$_NOT_")
-                       {
-                               SigBit A = sigmap(cell->getPort("\\A").as_bit());
-                               SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
-                               unused_bits.erase(A);
-                               undriven_bits.erase(Y);
-                               not_map[Y] = A;
-                               continue;
-                       }
-                       if (cell->type == "$_AND_")
-                       {
-                               SigBit A = sigmap(cell->getPort("\\A").as_bit());
-                               SigBit B = sigmap(cell->getPort("\\B").as_bit());
-                               SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
-                               unused_bits.erase(A);
-                               unused_bits.erase(B);
-                               undriven_bits.erase(Y);
-                               and_map[Y] = make_pair(A, B);
-                               continue;
-                       }
+                       RTLIL::Module* inst_module = module->design->module(cell->type);
+                       if (!cell->has_keep_attr()) {
+                               if (cell->type == "$_NOT_")
+                               {
+                                       SigBit A = sigmap(cell->getPort("\\A").as_bit());
+                                       SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
+                                       unused_bits.erase(A);
+                                       undriven_bits.erase(Y);
+                                       not_map[Y] = A;
+                                       continue;
+                               }
  
-                       if (cell->type == "$__ABC9_FF_" &&
-                                         // The presence of an abc9_mergeability attribute indicates
-                                         //   that we do want to pass this flop to ABC
-                                         cell->attributes.count("\\abc9_mergeability"))
-                       {
-                               SigBit D = sigmap(cell->getPort("\\D").as_bit());
-                               SigBit Q = sigmap(cell->getPort("\\Q").as_bit());
-                               unused_bits.erase(D);
-                               undriven_bits.erase(Q);
-                               alias_map[Q] = D;
-                               auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell));
-                               log_assert(r.second);
-                               continue;
-                       }
+                               if (cell->type == "$_AND_")
+                               {
+                                       SigBit A = sigmap(cell->getPort("\\A").as_bit());
+                                       SigBit B = sigmap(cell->getPort("\\B").as_bit());
+                                       SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
+                                       unused_bits.erase(A);
+                                       unused_bits.erase(B);
+                                       undriven_bits.erase(Y);
+                                       and_map[Y] = make_pair(A, B);
+                                       continue;
+                               }
  
-                       RTLIL::Module* inst_module = module->design->module(cell->type);
-                       if (inst_module && inst_module->get_blackbox_attribute()) {
-                               auto it = cell->attributes.find("\\abc9_box_seq");
-                               if (it != cell->attributes.end()) {
-                                       int abc9_box_seq = it->second.as_int();
-                                       if (GetSize(box_list) <= abc9_box_seq)
-                                               box_list.resize(abc9_box_seq+1);
-                                       box_list[abc9_box_seq] = cell;
-                                       // Only flop boxes may have arrival times
-                                       //   (all others are combinatorial)
-                                       if (!inst_module->get_bool_attribute("\\abc9_flop"))
-                                               continue;
+                               if (cell->type == "$__ABC9_FF_" &&
+                                               // The presence of an abc9_mergeability attribute indicates
+                                               //   that we do want to pass this flop to ABC
+                                               cell->attributes.count("\\abc9_mergeability"))
+                               {
+                                       SigBit D = sigmap(cell->getPort("\\D").as_bit());
+                                       SigBit Q = sigmap(cell->getPort("\\Q").as_bit());
+                                       unused_bits.erase(D);
+                                       undriven_bits.erase(Q);
+                                       alias_map[Q] = D;
+                                       auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell));
+                                       log_assert(r.second);
+                                       continue;
                                }
  
-                               for (const auto &conn : cell->connections()) {
-                                       auto port_wire = inst_module->wire(conn.first);
-                                       if (port_wire->port_output) {
-                                               arrivals.clear();
-                                               auto it = port_wire->attributes.find("\\abc9_arrival");
-                                               if (it == port_wire->attributes.end())
+                               if (inst_module) {
+                                       auto it = cell->attributes.find("\\abc9_box_seq");
+                                       if (it != cell->attributes.end()) {
+                                               int abc9_box_seq = it->second.as_int();
+                                               if (GetSize(box_list) <= abc9_box_seq)
+                                                       box_list.resize(abc9_box_seq+1);
+                                               box_list[abc9_box_seq] = cell;
+                                               // Only flop boxes may have arrival times
++                                              //   (all others are combinatorial)
+                                               if (!inst_module->get_bool_attribute("\\abc9_flop"))
                                                        continue;
-                                               if (it->second.flags == 0)
-                                                       arrivals.emplace_back(it->second.as_int());
-                                               else
-                                                       for (const auto &tok : split_tokens(it->second.decode_string()))
-                                                               arrivals.push_back(atoi(tok.c_str()));
+                                       }
 -                                      auto &cell_arrivals = arrival_cache[cell->type];
++                                      auto &cell_arrivals = arrivals_cache[cell->type];
+                                       for (const auto &conn : cell->connections()) {
++                                              auto port_wire = inst_module->wire(conn.first);
++                                              if (!port_wire->port_output)
++                                                      continue;
++
+                                               auto r = cell_arrivals.insert(conn.first);
 -                                              auto &arrival = r.first->second;
++                                              auto &arrivals = r.first->second;
+                                               if (r.second) {
 -                                                      auto port_wire = inst_module->wire(conn.first);
 -                                                      if (port_wire->port_output) {
 -                                                              auto it = port_wire->attributes.find("\\abc9_arrival");
 -                                                              if (it != port_wire->attributes.end()) {
 -                                                                      if (it->second.flags != 0)
 -                                                                              log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type));
 -                                                                      arrival = it->second.as_int();
 -                                                              }
 -                                                      }
++                                                      auto it = port_wire->attributes.find("\\abc9_arrival");
++                                                      if (it == port_wire->attributes.end())
++                                                              continue;
++                                                      if (it->second.flags == 0)
++                                                              arrivals.emplace_back(it->second.as_int());
++                                                      else
++                                                              for (const auto &tok : split_tokens(it->second.decode_string()))
++                                                                      arrivals.push_back(atoi(tok.c_str()));
++                                              }
++
 +                                              if (GetSize(arrivals) > 1 && GetSize(arrivals) != GetSize(port_wire))
 +                                                      log_error("%s.%s is %d bits wide but abc9_arrival = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first),
 +                                                                      GetSize(port_wire), log_signal(it->second), GetSize(arrivals));
-                                               auto jt = arrivals.begin();
 +
++                                              auto jt = arrivals.begin();
 +#ifndef NDEBUG
 +                                              if (ys_debug(1)) {
 +                                                      static std::set<std::pair<IdString,IdString>> seen;
 +                                                      if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_arrival = %d\n", log_id(cell->type), log_id(conn.first), *jt);
 +                                              }
 +#endif
 +                                              for (auto bit : sigmap(conn.second)) {
 +                                                      arrival_times[bit] = *jt;
 +                                                      if (arrivals.size() > 1)
 +                                                              jt++;
                                                }
 -                                              if (arrival)
 -                                                      for (auto bit : sigmap(conn.second))
 -                                                              arrival_times[bit] = arrival;
                                        }
                                }
                        }
index 1be7519b75999d7c845970c972ce6e6f76091e5a,6a296bfe7fa4b9d76e0257d06540f31785da6e59..5ba87fa88ba347732c1868277aee7317cd593112
@@@ -165,10 -222,14 +224,18 @@@ struct Abc9Pass : public ScriptPas
                                cleanup = false;
                                continue;
                        }
 +                      if (arg == "-box" && argidx+1 < args.size()) {
 +                              box_file = args[++argidx];
 +                              continue;
 +                      }
+                       if (arg == "-run" && argidx+1 < args.size()) {
+                               size_t pos = args[argidx+1].find(':');
+                               if (pos == std::string::npos)
+                                       break;
+                               run_from = args[++argidx].substr(0, pos);
+                               run_to = args[argidx].substr(pos+1);
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);
        void script() YS_OVERRIDE
        {
                if (check_label("pre")) {
 +                      run("abc9_ops -check");
                        run("scc -set_attr abc9_scc_id {}");
                        if (help_mode)
-                               run("abc9_ops -break_scc -prep_times -prep_holes [-dff]", "(option for -dff)");
 -                              run("abc9_ops -mark_scc -prep_xaiger [-dff]", "(option for -dff)");
++                              run("abc9_ops -mark_scc -prep_times -prep_xaiger [-dff]", "(option for -dff)");
                        else
-                               run("abc9_ops -break_scc -prep_times -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)");
 -                              run("abc9_ops -mark_scc -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)");
++                              run("abc9_ops -mark_scc -prep_times -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)");
                        run("select -set abc9_holes A:abc9_holes");
                        run("flatten -wb @abc9_holes");
                        run("techmap @abc9_holes");
                if (check_label("map")) {
                        if (help_mode) {
                                run("foreach module in selection");
-                               run("    abc9_ops -write_box [(-box value)|(null)] <abc-temp-dir>/input.box");
++                              run("    abc9_ops -write_box [(-box <path>)|(null)] <abc-temp-dir>/input.box");
                                run("    write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig");
 -                              run("    abc9_exe -cwd <abc-temp-dir> [options]");
 +                              run("    abc9_exe [options] -cwd <abc-temp-dir> -box <abc-temp-dir>/input.box");
                                run("    read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig");
                                run("    abc9_ops -reintegrate");
                        }
                                                        active_design->scratchpad_get_int("write_xaiger.num_inputs"),
                                                        num_outputs);
                                        if (num_outputs) {
 -                                              run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()));
 +                                              run(stringf("%s -cwd %s -box %s/input.box", exe_cmd.str().c_str(), tempdir_name.c_str(), tempdir_name.c_str()));
-                                               run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str()));
+                                               run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str()));
                                                run("abc9_ops -reintegrate");
                                        }
                                        else
index 7f3bbc7ad56c65f598669119cdfba86d0c871323,463941b0b1b2dc9e54aa98c2bc07fbf91455ae00..04a54fd6301f84bb040f727c0765ee343cdd2806
@@@ -35,63 -33,7 +35,63 @@@ inline std::string remap_name(RTLIL::Id
        return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1);
  }
  
- void break_scc(RTLIL::Module *module)
 +void check(RTLIL::Design *design)
 +{
 +      dict<IdString,IdString> box_lookup;
 +      for (auto m : design->modules()) {
 +              auto flop = m->get_bool_attribute(ID(abc9_flop));
 +              auto it = m->attributes.find(ID(abc9_box_id));
 +              if (it == m->attributes.end()) {
 +                      if (flop)
 +                              log_error("Module '%s' contains (* abc9_flop *) but not (* abc9_box_id=<int> *).\n", log_id(m));
 +                      continue;
 +              }
 +              if (m->name.begins_with("$paramod"))
 +                      continue;
 +              auto id = it->second.as_int();
 +              auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name));
 +              if (!r.second)
 +                      log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n",
 +                                      log_id(m), id, log_id(r.first->second));
 +
 +              // Make carry in the last PI, and carry out the last PO
 +              //   since ABC requires it this way
 +              IdString carry_in, carry_out;
 +              for (const auto &port_name : m->ports) {
 +                      auto w = m->wire(port_name);
 +                      log_assert(w);
 +                      if (w->get_bool_attribute("\\abc9_carry")) {
 +                              if (w->port_input) {
 +                                      if (carry_in != IdString())
 +                                              log_error("Module '%s' contains more than one (* abc9_carry *) input port.\n", log_id(m));
 +                                      carry_in = port_name;
 +                              }
 +                              if (w->port_output) {
 +                                      if (carry_out != IdString())
 +                                              log_error("Module '%s' contains more than one (* abc9_carry *) output port.\n", log_id(m));
 +                                      carry_out = port_name;
 +                              }
 +                      }
 +              }
 +
 +              if (carry_in != IdString() && carry_out == IdString())
 +                      log_error("Module '%s' contains an (* abc9_carry *) input port but no output port.\n", log_id(m));
 +              if (carry_in == IdString() && carry_out != IdString())
 +                      log_error("Module '%s' contains an (* abc9_carry *) output port but no input port.\n", log_id(m));
 +
 +              if (flop) {
 +                      int num_outputs = 0;
 +                      for (auto port_name : m->ports) {
 +                              auto wire = m->wire(port_name);
 +                              if (wire->port_output) num_outputs++;
 +                      }
 +                      if (num_outputs != 1)
 +                              log_error("Module '%s' with (* abc_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs);
 +              }
 +      }
 +}
 +
+ void mark_scc(RTLIL::Module *module)
  {
        // For every unique SCC found, (arbitrarily) find the first
        //   cell in the component, and convert all wires driven by
@@@ -648,19 -356,53 +568,21 @@@ void reintegrate(RTLIL::Module *module
                if (m->name.begins_with("$paramod"))
                        continue;
                auto id = it->second.as_int();
 -              auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name));
 -              if (!r.second)
 -                      log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n",
 -                                      log_id(m), id, log_id(r.first->second));
 +              auto r YS_ATTRIBUTE(unused) = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name));
                log_assert(r.second);
 -
 -              auto r2 = box_ports.insert(m->name);
 -              if (r2.second) {
 -                      // Make carry in the last PI, and carry out the last PO
 -                      //   since ABC requires it this way
 -                      IdString carry_in, carry_out;
 -                      for (const auto &port_name : m->ports) {
 -                              auto w = m->wire(port_name);
 -                              log_assert(w);
 -                              if (w->get_bool_attribute("\\abc9_carry")) {
 -                                      if (w->port_input) {
 -                                              if (carry_in != IdString())
 -                                                      log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m));
 -                                              carry_in = port_name;
 -                                      }
 -                                      if (w->port_output) {
 -                                              if (carry_out != IdString())
 -                                                      log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(m));
 -                                              carry_out = port_name;
 -                                      }
 -                              }
 -                              else
 -                                      r2.first->second.push_back(port_name);
 -                      }
 -
 -                      if (carry_in != IdString() && carry_out == IdString())
 -                              log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m));
 -                      if (carry_in == IdString() && carry_out != IdString())
 -                              log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m));
 -                      if (carry_in != IdString()) {
 -                              r2.first->second.push_back(carry_in);
 -                              r2.first->second.push_back(carry_out);
 -                      }
 -              }
        }
  
 +      pool<IdString> delay_boxes;
        std::vector<Cell*> boxes;
        for (auto cell : module->cells().to_vector()) {
+               if (cell->has_keep_attr())
+                       continue;
                if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))
                        module->remove(cell);
 +              else if (cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) {
 +                      delay_boxes.insert(cell->name);
 +                      module->remove(cell);
 +              }
                else if (cell->attributes.erase("\\abc9_box_seq"))
                        boxes.emplace_back(cell);
        }
                                }
                                if (cell->output(mapped_conn.first))
                                        for (auto i : mapped_conn.second)
-                                               bit_drivers[i].insert(mapped_cell->name);
+                                               // Ignore inouts for topo ordering
+                                               if (i.wire && !(i.wire->port_input && i.wire->port_output))
+                                                       bit_drivers[i].insert(mapped_cell->name);
                        }
                }
 +              else if (delay_boxes.count(mapped_cell->name)) {
 +                      SigBit I = mapped_cell->getPort(ID(i));
 +                      SigBit O = mapped_cell->getPort(ID(o));
 +                      if (I.wire)
 +                              I.wire = module->wires_.at(remap_name(I.wire->name));
 +                      log_assert(O.wire);
 +                      O.wire = module->wires_.at(remap_name(O.wire->name));
 +                      module->connect(O, I);
 +                      continue;
 +              }
                else {
                        RTLIL::Cell *existing_cell = module->cell(mapped_cell->name);
                        log_assert(existing_cell);
                                for (const auto &i : inputs)
                                        bit_users[i].insert(mapped_cell->name);
                                for (const auto &i : outputs)
-                                       bit_drivers[i].insert(mapped_cell->name);
+                                       // Ignore inouts for topo ordering
+                                       if (i.wire && !(i.wire->port_input && i.wire->port_output))
+                                               bit_drivers[i].insert(mapped_cell->name);
                        }
  
 +                      auto r2 = box_ports.insert(cell->type);
 +                      if (r2.second) {
 +                              // Make carry in the last PI, and carry out the last PO
 +                              //   since ABC requires it this way
 +                              IdString carry_in, carry_out;
 +                              for (const auto &port_name : box_module->ports) {
 +                                      auto w = box_module->wire(port_name);
 +                                      log_assert(w);
 +                                      if (w->get_bool_attribute("\\abc9_carry")) {
 +                                              if (w->port_input)
 +                                                      carry_in = port_name;
 +                                              if (w->port_output)
 +                                                      carry_out = port_name;
 +                                      }
 +                                      else
 +                                              r2.first->second.push_back(port_name);
 +                              }
 +
 +                              if (carry_in != IdString()) {
 +                                      r2.first->second.push_back(carry_in);
 +                                      r2.first->second.push_back(carry_out);
 +                              }
 +                      }
 +
                        int input_count = 0, output_count = 0;
                        for (const auto &port_name : box_ports.at(cell->type)) {
                                RTLIL::Wire *w = box_module->wire(port_name);
@@@ -1001,50 -757,27 +962,45 @@@ struct Abc9OpsPass : public Pass 
        {
                log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n");
  
-               bool break_scc_mode = false;
-               bool unbreak_scc_mode = false;
-               bool prep_holes_mode = false;
 +              bool check_mode = false;
 +              bool prep_times_mode = false;
+               bool mark_scc_mode = false;
                bool prep_dff_mode = false;
-               std::string write_box_src, write_box_dst;
+               bool prep_xaiger_mode = false;
                bool reintegrate_mode = false;
                bool dff_mode = false;
++              std::string write_box_src, write_box_dst;
  
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++) {
                        std::string arg = args[argidx];
-                       if (arg == "-break_scc") {
-                               break_scc_mode = true;
-                               continue;
-                       }
-                       if (arg == "-unbreak_scc") {
-                               unbreak_scc_mode = true;
 +                      if (arg == "-check") {
 +                              check_mode = true;
 +                              continue;
 +                      }
+                       if (arg == "-mark_scc") {
+                               mark_scc_mode = true;
                                continue;
                        }
                        if (arg == "-prep_dff") {
                                prep_dff_mode = true;
                                continue;
                        }
-                       if (arg == "-prep_holes") {
-                               prep_holes_mode = true;
+                       if (arg == "-prep_xaiger") {
+                               prep_xaiger_mode = true;
                                continue;
                        }
 +                      if (arg == "-prep_times") {
 +                              prep_times_mode = true;
 +                              continue;
 +                      }
 +                      if (arg == "-write_box" && argidx+2 < args.size()) {
 +                              write_box_src = args[++argidx];
 +                              write_box_dst = args[++argidx];
 +                              rewrite_filename(write_box_src);
 +                              rewrite_filename(write_box_dst);
 +                              continue;
 +                      }
                        if (arg == "-reintegrate") {
                                reintegrate_mode = true;
                                continue;
                }
                extra_args(args, argidx, design);
  
-               if (!(check_mode || break_scc_mode || unbreak_scc_mode || prep_times_mode || prep_holes_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode))
-                       log_cmd_error("At least one of -check, -{,un}break_scc, -prep_{times,holes,dff}, -write_box, -reintegrate must be specified.\n");
 -              if (!(mark_scc_mode || prep_dff_mode || reintegrate_mode))
 -                      log_cmd_error("At least one of -mark_scc, -prep_{xaiger,dff}, -reintegrate must be specified.\n");
++              if (!(check_mode || mark_scc_mode || prep_times_mode || prep_xaiger_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode))
++                      log_cmd_error("At least one of -check, -mark_scc, -prep_{times,xaiger,dff}, -write_box, -reintegrate must be specified.\n");
  
-               if (dff_mode && !prep_holes_mode)
-                       log_cmd_error("'-dff' option is only relevant for -prep_holes.\n");
+               if (dff_mode && !prep_xaiger_mode)
+                       log_cmd_error("'-dff' option is only relevant for -prep_xaiger.\n");
  
 +              if (check_mode)
 +                      check(design);
 +              if (prep_times_mode)
 +                      prep_times(design);
 +
                for (auto mod : design->selected_modules()) {
                        if (mod->get_bool_attribute("\\abc9_holes"))
                                continue;
                        if (!design->selected_whole_module(mod))
                                log_error("Can't handle partially selected module %s!\n", log_id(mod));
  
-                       if (break_scc_mode)
-                               break_scc(mod);
-                       if (unbreak_scc_mode)
-                               unbreak_scc(mod);
-                       if (prep_holes_mode)
-                               prep_holes(mod, dff_mode);
-                       if (prep_dff_mode)
-                               prep_dff(mod);
 +                      if (!write_box_src.empty())
 +                              write_box(mod, write_box_src, write_box_dst);
+                       if (mark_scc_mode)
+                               mark_scc(mod);
+                       if (prep_dff_mode)
+                               prep_dff(mod);
+                       if (prep_xaiger_mode)
+                               prep_xaiger(mod, dff_mode);
                        if (reintegrate_mode)
                                reintegrate(mod);
                }