diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index eb793ba2d..844df084f 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc @@ -575,7 +575,7 @@ struct LibertyFrontend : public Frontend { for (auto &attr : attributes) module->attributes[attr] = 1; - bool simple_comb_cell = true, has_outputs = false; + bool simple_comb_cell = true, has_inputs = false, has_outputs = false; for (auto node : cell->children) { @@ -693,6 +693,7 @@ struct LibertyFrontend : public Frontend { } if (dir && dir->value == "input") { + has_inputs = true; wire->port_input = true; continue; } @@ -736,7 +737,7 @@ struct LibertyFrontend : public Frontend { simple_comb_cell = false; } - if (simple_comb_cell && has_outputs && flag_unit_delay) { + if (simple_comb_cell && has_inputs && has_outputs && flag_unit_delay) { module->set_bool_attribute(ID::abc9_box); for (auto wi : module->wires()) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 21059c774..4faa981c3 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -33,23 +33,33 @@ void check(RTLIL::Design *design, bool dff_mode) dict box_lookup; for (auto m : design->modules()) { auto flop = m->get_bool_attribute(ID::abc9_flop); + auto box = m->get_bool_attribute(ID::abc9_box); auto it = m->attributes.find(ID::abc9_box_id); if (!flop) { - if (it == m->attributes.end()) + if (!box && it == m->attributes.end()) 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", - m, id, r.first->second.unescape()); + if (it != m->attributes.end()) { + 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", + m, id, r.first->second.unescape()); + } } // Make carry in the last PI, and carry out the last PO // since ABC requires it this way IdString carry_in, carry_out; + bool has_input = false, has_output = false; for (const auto &port_name : m->ports) { auto w = m->wire(port_name); log_assert(w); + if (GetSize(w)) { + if (w->port_input) + has_input = true; + if (w->port_output) + has_output = true; + } if (w->get_bool_attribute(ID::abc9_carry)) { if (w->port_input) { if (carry_in != IdString()) @@ -69,6 +79,13 @@ void check(RTLIL::Design *design, bool dff_mode) if (carry_in == IdString() && carry_out != IdString()) log_error("Module '%s' contains an (* abc9_carry *) output port but no input port.\n", m); + // A timing arc spans an input to an output, so a box missing either + // carries no timing for abc to work with + if (!flop && !has_input) + log_error("Module '%s' with (* abc9_box *) has no input port.\n", m); + if (!flop && !has_output) + log_error("Module '%s' with (* abc9_box *) has no output port.\n", m); + if (flop) { int num_outputs = 0; for (auto port_name : m->ports) { diff --git a/tests/abc_new/box_no_input.ys b/tests/abc_new/box_no_input.ys new file mode 100644 index 000000000..b1f40ec3b --- /dev/null +++ b/tests/abc_new/box_no_input.ys @@ -0,0 +1,15 @@ +# an abc9 box needs an input, or it can carry no timing arcs +logger -expect error "has no input port" 1 +read_verilog -specify <