diff options
Diffstat (limited to 'techlibs/coolrunner2/coolrunner2_sop.cc')
-rw-r--r-- | techlibs/coolrunner2/coolrunner2_sop.cc | 258 |
1 files changed, 89 insertions, 169 deletions
diff --git a/techlibs/coolrunner2/coolrunner2_sop.cc b/techlibs/coolrunner2/coolrunner2_sop.cc index de0cbb29d..045c73978 100644 --- a/techlibs/coolrunner2/coolrunner2_sop.cc +++ b/techlibs/coolrunner2/coolrunner2_sop.cc @@ -47,52 +47,54 @@ struct Coolrunner2SopPass : public Pass { dict<SigBit, tuple<SigBit, Cell*>> not_cells; for (auto cell : module->selected_cells()) { - if (cell->type == "$_NOT_") + if (cell->type == ID($_NOT_)) { - auto not_input = sigmap(cell->getPort("\\A")[0]); - auto not_output = sigmap(cell->getPort("\\Y")[0]); + auto not_input = sigmap(cell->getPort(ID::A)[0]); + auto not_output = sigmap(cell->getPort(ID::Y)[0]); not_cells[not_input] = tuple<SigBit, Cell*>(not_output, cell); } } // Find wires that need to become special product terms - dict<SigBit, pool<tuple<Cell*, std::string>>> special_pterms_no_inv; - dict<SigBit, pool<tuple<Cell*, std::string>>> special_pterms_inv; + dict<SigBit, pool<tuple<Cell*, IdString>>> special_pterms_no_inv; + dict<SigBit, pool<tuple<Cell*, IdString>>> special_pterms_inv; for (auto cell : module->selected_cells()) { - if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\FTCP", "\\FTCP_N", "\\FTDCP", - "\\FDCPE", "\\FDCPE_N", "\\FDDCPE", "\\LDCP", "\\LDCP_N")) + if (cell->type.in(ID(FDCP), ID(FDCP_N), ID(FDDCP), ID(FTCP), ID(FTCP_N), ID(FTDCP), + ID(FDCPE), ID(FDCPE_N), ID(FDDCPE), ID(LDCP), ID(LDCP_N))) { - if (cell->hasPort("\\PRE")) - special_pterms_no_inv[sigmap(cell->getPort("\\PRE")[0])].insert( - tuple<Cell*, const char *>(cell, "\\PRE")); - if (cell->hasPort("\\CLR")) - special_pterms_no_inv[sigmap(cell->getPort("\\CLR")[0])].insert( - tuple<Cell*, const char *>(cell, "\\CLR")); - if (cell->hasPort("\\CE")) - special_pterms_no_inv[sigmap(cell->getPort("\\CE")[0])].insert( - tuple<Cell*, const char *>(cell, "\\CE")); - - if (cell->hasPort("\\C")) - special_pterms_inv[sigmap(cell->getPort("\\C")[0])].insert( - tuple<Cell*, const char *>(cell, "\\C")); - if (cell->hasPort("\\G")) - special_pterms_inv[sigmap(cell->getPort("\\G")[0])].insert( - tuple<Cell*, const char *>(cell, "\\G")); + if (cell->hasPort(ID(PRE))) + special_pterms_no_inv[sigmap(cell->getPort(ID(PRE))[0])].insert( + make_tuple(cell, ID(PRE))); + if (cell->hasPort(ID::CLR)) + special_pterms_no_inv[sigmap(cell->getPort(ID::CLR)[0])].insert( + make_tuple(cell, ID::CLR)); + if (cell->hasPort(ID(CE))) + special_pterms_no_inv[sigmap(cell->getPort(ID(CE))[0])].insert( + make_tuple(cell, ID(CE))); + + if (cell->hasPort(ID::C)) + special_pterms_inv[sigmap(cell->getPort(ID::C)[0])].insert( + make_tuple(cell, ID::C)); + if (cell->hasPort(ID::G)) + special_pterms_inv[sigmap(cell->getPort(ID::G)[0])].insert( + make_tuple(cell, ID::G)); } } // Process $sop cells for (auto cell : module->selected_cells()) { - if (cell->type == "$sop") + if (cell->type == ID($sop)) { // Read the inputs/outputs/parameters of the $sop cell - auto sop_inputs = sigmap(cell->getPort("\\A")); - auto sop_output = sigmap(cell->getPort("\\Y"))[0]; - auto sop_depth = cell->getParam("\\DEPTH").as_int(); - auto sop_width = cell->getParam("\\WIDTH").as_int(); - auto sop_table = cell->getParam("\\TABLE"); + auto sop_inputs = sigmap(cell->getPort(ID::A)); + auto sop_output = sigmap(cell->getPort(ID::Y))[0]; + auto sop_depth = cell->getParam(ID::DEPTH).as_int(); + auto sop_width = cell->getParam(ID::WIDTH).as_int(); + auto sop_table = cell->getParam(ID::TABLE); + + auto sop_output_wire_name = sop_output.wire->name.c_str(); // Check for a $_NOT_ at the output bool has_invert = false; @@ -108,20 +110,15 @@ struct Coolrunner2SopPass : public Pass { } // Check for special P-term usage - bool is_special_pterm = false; - bool special_pterm_can_invert = false; - if (special_pterms_no_inv.count(sop_output) || special_pterms_inv.count(sop_output)) - { - is_special_pterm = true; - if (!special_pterms_no_inv[sop_output].size()) - special_pterm_can_invert = true; - } + bool is_special_pterm = + special_pterms_no_inv.count(sop_output) || special_pterms_inv.count(sop_output); // Construct AND cells pool<SigBit> intermed_wires; for (int i = 0; i < sop_depth; i++) { // Wire for the output - auto and_out = module->addWire(NEW_ID); + auto and_out = module->addWire( + module->uniquify(stringf("$xc2sop$%s_AND%d_OUT", sop_output_wire_name, i))); intermed_wires.insert(and_out); // Signals for the inputs @@ -140,107 +137,84 @@ struct Coolrunner2SopPass : public Pass { } // Construct the cell - auto and_cell = module->addCell(NEW_ID, "\\ANDTERM"); - and_cell->setParam("\\TRUE_INP", GetSize(and_in_true)); - and_cell->setParam("\\COMP_INP", GetSize(and_in_comp)); - and_cell->setPort("\\OUT", and_out); - and_cell->setPort("\\IN", and_in_true); - and_cell->setPort("\\IN_B", and_in_comp); + auto and_cell = module->addCell( + module->uniquify(stringf("$xc2sop$%s_AND%d", sop_output_wire_name, i)), + ID(ANDTERM)); + and_cell->setParam(ID(TRUE_INP), GetSize(and_in_true)); + and_cell->setParam(ID(COMP_INP), GetSize(and_in_comp)); + and_cell->setPort(ID(OUT), and_out); + and_cell->setPort(ID(IN), and_in_true); + and_cell->setPort(ID(IN_B), and_in_comp); } if (sop_depth == 1) { // If there is only one term, don't construct an OR cell. Directly construct the XOR gate - auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_OUT", has_invert); - xor_cell->setPort("\\IN_PTC", *intermed_wires.begin()); - xor_cell->setPort("\\OUT", sop_output); + auto xor_cell = module->addCell( + module->uniquify(stringf("$xc2sop$%s_XOR", sop_output_wire_name)), + ID(MACROCELL_XOR)); + xor_cell->setParam(ID(INVERT_OUT), has_invert); + xor_cell->setPort(ID(IN_PTC), *intermed_wires.begin()); + xor_cell->setPort(ID(OUT), sop_output); // Special P-term handling if (is_special_pterm) { - if (!has_invert || special_pterm_can_invert) + // Can always connect the P-term directly if it's going + // into something invert-capable + for (const auto &x : special_pterms_inv[sop_output]) { - // Can connect the P-term directly to the special term sinks - for (auto x : special_pterms_inv[sop_output]) - std::get<0>(x)->setPort(std::get<1>(x), *intermed_wires.begin()); - for (auto x : special_pterms_no_inv[sop_output]) - std::get<0>(x)->setPort(std::get<1>(x), *intermed_wires.begin()); - } + std::get<0>(x)->setPort(std::get<1>(x), *intermed_wires.begin()); - if (has_invert) - { - if (special_pterm_can_invert) + // If this signal is indeed inverted, flip the cell polarity + if (has_invert) { - log_assert(special_pterms_no_inv[sop_output].size() == 0); - - for (auto x : special_pterms_inv[sop_output]) - { - auto cell = std::get<0>(x); - // Need to invert the polarity of the cell - if (cell->type == "\\FDCP") cell->type = "\\FDCP_N"; - else if (cell->type == "\\FDCP_N") cell->type = "\\FDCP"; - else if (cell->type == "\\FTCP") cell->type = "\\FTCP_N"; - else if (cell->type == "\\FTCP_N") cell->type = "\\FTCP"; - else if (cell->type == "\\FDCPE") cell->type = "\\FDCPE_N"; - else if (cell->type == "\\FDCPE_N") cell->type = "\\FDCPE"; - else if (cell->type == "\\LDCP") cell->type = "\\LDCP_N"; - else if (cell->type == "\\LDCP_N") cell->type = "\\LDCP"; - else log_assert(!"Internal error! Bad cell type!"); - } + auto cell = std::get<0>(x); + if (cell->type == ID(FDCP)) cell->type = ID(FDCP_N); + else if (cell->type == ID(FDCP_N)) cell->type = ID(FDCP); + else if (cell->type == ID(FTCP)) cell->type = ID(FTCP_N); + else if (cell->type == ID(FTCP_N)) cell->type = ID(FTCP); + else if (cell->type == ID(FDCPE)) cell->type = ID(FDCPE_N); + else if (cell->type == ID(FDCPE_N)) cell->type = ID(FDCPE); + else if (cell->type == ID(LDCP)) cell->type = ID(LDCP_N); + else if (cell->type == ID(LDCP_N)) cell->type = ID(LDCP); + else log_assert(!"Internal error! Bad cell type!"); } - else - { - // Need to construct a feed-through term - auto feedthrough_out = module->addWire(NEW_ID); - auto feedthrough_cell = module->addCell(NEW_ID, "\\ANDTERM"); - feedthrough_cell->setParam("\\TRUE_INP", 1); - feedthrough_cell->setParam("\\COMP_INP", 0); - feedthrough_cell->setPort("\\OUT", feedthrough_out); - feedthrough_cell->setPort("\\IN", sop_output); - feedthrough_cell->setPort("\\IN_B", SigSpec()); + } - for (auto x : special_pterms_inv[sop_output]) - std::get<0>(x)->setPort(std::get<1>(x), feedthrough_out); - for (auto x : special_pterms_no_inv[sop_output]) - std::get<0>(x)->setPort(std::get<1>(x), feedthrough_out); - } + // If it's going into something that's not invert-capable, + // connect it directly only if this signal isn't inverted + if (!has_invert) + { + for (auto x : special_pterms_no_inv[sop_output]) + std::get<0>(x)->setPort(std::get<1>(x), *intermed_wires.begin()); } + + // Otherwise, a feedthrough P-term has to be created. Leave that to happen + // in the coolrunner2_fixup pass. } } else { // Wire from OR to XOR - auto or_to_xor_wire = module->addWire(NEW_ID); + auto or_to_xor_wire = module->addWire( + module->uniquify(stringf("$xc2sop$%s_OR_OUT", sop_output_wire_name))); // Construct the OR cell - auto or_cell = module->addCell(NEW_ID, "\\ORTERM"); - or_cell->setParam("\\WIDTH", sop_depth); - or_cell->setPort("\\IN", intermed_wires); - or_cell->setPort("\\OUT", or_to_xor_wire); + auto or_cell = module->addCell( + module->uniquify(stringf("$xc2sop$%s_OR", sop_output_wire_name)), + ID(ORTERM)); + or_cell->setParam(ID::WIDTH, sop_depth); + or_cell->setPort(ID(IN), intermed_wires); + or_cell->setPort(ID(OUT), or_to_xor_wire); // Construct the XOR cell - auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_OUT", has_invert); - xor_cell->setPort("\\IN_ORTERM", or_to_xor_wire); - xor_cell->setPort("\\OUT", sop_output); - - if (is_special_pterm) - { - // Need to construct a feed-through term - auto feedthrough_out = module->addWire(NEW_ID); - auto feedthrough_cell = module->addCell(NEW_ID, "\\ANDTERM"); - feedthrough_cell->setParam("\\TRUE_INP", 1); - feedthrough_cell->setParam("\\COMP_INP", 0); - feedthrough_cell->setPort("\\OUT", feedthrough_out); - feedthrough_cell->setPort("\\IN", sop_output); - feedthrough_cell->setPort("\\IN_B", SigSpec()); - - for (auto x : special_pterms_inv[sop_output]) - std::get<0>(x)->setPort(std::get<1>(x), feedthrough_out); - for (auto x : special_pterms_no_inv[sop_output]) - std::get<0>(x)->setPort(std::get<1>(x), feedthrough_out); - } + auto xor_cell = module->addCell( + module->uniquify(stringf("$xc2sop$%s_XOR", sop_output_wire_name)), + ID(MACROCELL_XOR)); + xor_cell->setParam(ID(INVERT_OUT), has_invert); + xor_cell->setPort(ID(IN_ORTERM), or_to_xor_wire); + xor_cell->setPort(ID(OUT), sop_output); } // Finally, remove the $sop cell @@ -248,60 +222,6 @@ struct Coolrunner2SopPass : public Pass { } } - // In some cases we can get a FF feeding straight into an FF. This is not possible, so we need to insert - // some AND/XOR cells in the middle to make it actually work. - - // Find all the FF outputs - pool<SigBit> sig_fed_by_ff; - for (auto cell : module->selected_cells()) - { - if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N", - "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE")) - { - auto output = sigmap(cell->getPort("\\Q")[0]); - sig_fed_by_ff.insert(output); - } - } - - // Look at all the FF inputs - for (auto cell : module->selected_cells()) - { - if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N", - "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE")) - { - SigBit input; - if (cell->type.in("\\FTCP", "\\FTCP_N", "\\FTDCP")) - input = sigmap(cell->getPort("\\T")[0]); - else - input = sigmap(cell->getPort("\\D")[0]); - - if (sig_fed_by_ff[input]) - { - printf("Buffering input to \"%s\"\n", cell->name.c_str()); - - auto and_to_xor_wire = module->addWire(NEW_ID); - auto xor_to_ff_wire = module->addWire(NEW_ID); - - auto and_cell = module->addCell(NEW_ID, "\\ANDTERM"); - and_cell->setParam("\\TRUE_INP", 1); - and_cell->setParam("\\COMP_INP", 0); - and_cell->setPort("\\OUT", and_to_xor_wire); - and_cell->setPort("\\IN", input); - and_cell->setPort("\\IN_B", SigSpec()); - - auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_OUT", false); - xor_cell->setPort("\\IN_PTC", and_to_xor_wire); - xor_cell->setPort("\\OUT", xor_to_ff_wire); - - if (cell->type.in("\\FTCP", "\\FTCP_N", "\\FTDCP")) - cell->setPort("\\T", xor_to_ff_wire); - else - cell->setPort("\\D", xor_to_ff_wire); - } - } - } - // Actually do the removal now that we aren't iterating for (auto cell : cells_to_remove) { |