diff options
-rw-r--r-- | backends/aiger/xaiger.cc | 9 | ||||
-rw-r--r-- | passes/techmap/abc9_ops.cc | 48 | ||||
-rw-r--r-- | passes/techmap/iopadmap.cc | 9 | ||||
-rw-r--r-- | techlibs/xilinx/abc9_map.v | 23 | ||||
-rw-r--r-- | tests/techmap/iopadmap.ys | 37 |
5 files changed, 97 insertions, 29 deletions
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 76b7efbfc..9b2bab95c 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -643,14 +643,13 @@ struct XAigerWriter write_s_buffer(ff_bits.size()); for (const auto &i : ff_bits) { - const SigBit &d = i.first; const Cell *cell = i.second; int mergeability = cell->attributes.at(ID(abc9_mergeability)).as_int(); log_assert(mergeability > 0); write_r_buffer(mergeability); - Const init = cell->attributes.at(ID(abc9_init)); + Const init = cell->attributes.at(ID(abc9_init), State::Sx); log_assert(GetSize(init) == 1); if (init == State::S1) write_s_buffer(1); @@ -661,7 +660,11 @@ struct XAigerWriter write_s_buffer(0); } - write_i_buffer(arrival_times.at(d, 0)); + auto it = cell->attributes.find(ID(abc9_arrival)); + if (it != cell->attributes.end()) + write_i_buffer(it->second.as_int()); + else + write_i_buffer(0); //write_o_buffer(0); } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 7071f0de4..b26ea6720 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -192,20 +192,9 @@ void prep_dff(RTLIL::Module *module) clkdomain_t key(abc9_clock); auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); - auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second)); - log_assert(r2.second); - - Wire *abc9_init_wire = module->wire(stringf("%s.init", cell->name.c_str())); - if (abc9_init_wire == NULL) - log_error("'%s.init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - log_assert(GetSize(abc9_init_wire) == 1); - SigSpec abc9_init = assign_map(abc9_init_wire); - if (!abc9_init.is_fully_const()) - log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - if (abc9_init == State::S1) - log_error("'%s.init' in module '%s' has value 1'b1 which is not supported by 'abc9 -dff'.\n", cell->name.c_str(), log_id(module)); - r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); + auto r2 = cell->attributes.insert(ID(abc9_mergeability));; log_assert(r2.second); + r2.first->second = r.first->second; } RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str())); @@ -265,13 +254,19 @@ void prep_xaiger(RTLIL::Module *module, bool dff) SigMap sigmap(module); + dict<SigBit, Cell*> abc9_ff_d; dict<SigBit, pool<IdString>> bit_drivers, bit_users; TopoSort<IdString, RTLIL::sort_by_id_str> toposort; dict<IdString, std::vector<IdString>> box_ports; for (auto cell : module->cells()) { - if (cell->type == "$__ABC9_FF_") + if (cell->type == "$__ABC9_FF_") { + auto d = sigmap(cell->getPort(ID(D))); + auto r = abc9_ff_d.insert(d); + log_assert(r.second); + r.first->second = cell; continue; + } if (cell->has_keep_attr()) continue; @@ -368,6 +363,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) IdString derived_type = box_module->derive(design, cell->parameters); box_module = design->module(derived_type); + auto abc9_flop = box_module->get_bool_attribute("\\abc9_flop"); auto r = cell_cache.insert(derived_type); auto &holes_cell = r.first->second; @@ -406,7 +402,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) // For flops only, create an extra 1-bit input that drives a new wire // called "<cell>.abc9_ff.Q" that is used below - if (box_module->get_bool_attribute("\\abc9_flop")) { + if (abc9_flop) { box_inputs++; Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); if (!holes_wire) { @@ -436,6 +432,28 @@ void prep_xaiger(RTLIL::Module *module, bool dff) holes_module->connect(holes_wire, holes_cell->getPort(port_name)); else // blackbox holes_module->connect(holes_wire, Const(State::S0, GetSize(w))); + + // Transfer abc9_arrival value from flop box output to $__ABC9_FF_ cell + if (abc9_flop) { + auto it = w->attributes.find(ID(abc9_arrival)); + if (it == w->attributes.end()) + continue; + auto jt = cell->connections_.find(port_name); + if (jt == cell->connections_.end()) + continue; + auto kt = abc9_ff_d.find(jt->second); + if (kt == abc9_ff_d.end()) + continue; +#ifndef NDEBUG + if (ys_debug(1)) { + static std::set<std::pair<IdString,IdString>> seen; + if (seen.emplace(cell->type, port_name).second) log("%s.%s abc9_arrival = %d\n", log_id(cell->type), log_id(port_name), it->second.as_int()); + } +#endif + auto r = kt->second->attributes.insert(ID(abc9_arrival)); + log_assert(r.second); + r.first->second = it->second; + } } } } diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index 531ac2b99..a6e4fac14 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -423,6 +423,15 @@ struct IopadmapPass : public Pass { } } + if (wire->port_output) { + auto jt = new_wire->attributes.find(ID(init)); + // For output ports, move \init attributes from old wire to new wire + if (jt != new_wire->attributes.end()) { + wire->attributes[ID(init)] = std::move(jt->second); + new_wire->attributes.erase(jt); + } + } + wire->port_id = 0; wire->port_input = false; wire->port_output = false; diff --git a/techlibs/xilinx/abc9_map.v b/techlibs/xilinx/abc9_map.v index 539fa4547..f2c401d66 100644 --- a/techlibs/xilinx/abc9_map.v +++ b/techlibs/xilinx/abc9_map.v @@ -68,9 +68,10 @@ // (c) a special abc9_ff.clock wire to capture its clock domain and polarity // (indicated to `abc9' so that it only performs sequential synthesis // (with reachability analysis) correctly on one domain at a time) -// (d) a special abc9_ff.init wire to encode the flop's initial state -// NOTE: in order to perform sequential synthesis, `abc9' also requires -// that the initial value of all flops be zero +// (d) an (* abc9_init *) attribute on the $__ABC9_FF_ cell capturing its +// initial state +// NOTE: in order to perform sequential synthesis, `abc9' requires that +// the initial value of all flops be zero // (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback // into the (combinatorial) FD* cell to facilitate clock-enable behaviour @@ -103,11 +104,11 @@ module FDRE (output Q, (* techmap_autopurge *) input C, CE, D, R); ); end endgenerate + (* abc9_init = 1'b0 *) $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); // Special signals wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] abc9_ff.init = 1'b0; wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; endmodule module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R); @@ -130,11 +131,11 @@ module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R); ); end endgenerate + (* abc9_init = 1'b0 *) $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); // Special signals wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] abc9_ff.init = 1'b0; wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; endmodule @@ -166,11 +167,11 @@ module FDSE (output Q, (* techmap_autopurge *) input C, CE, D, S); .D(D), .Q($Q), .C(C), .CE(CE), .S(S) ); end endgenerate + (* abc9_init = 1'b0 *) $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); // Special signals wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] abc9_ff.init = 1'b0; wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; endmodule module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S); @@ -192,11 +193,11 @@ module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S); .D(D), .Q($Q), .C(C), .CE(CE), .S(S) ); end endgenerate + (* abc9_init = 1'b0 *) $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); // Special signals wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] abc9_ff.init = 1'b0; wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; endmodule @@ -242,11 +243,11 @@ module FDCE (output Q, (* techmap_autopurge *) input C, CE, D, CLR); // Since this is an async flop, async behaviour is dealt with here $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ)); end endgenerate + (* abc9_init = 1'b0 *) $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); // Special signals wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] abc9_ff.init = 1'b0; wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; endmodule module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR); @@ -280,11 +281,11 @@ module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR); ); $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR), .Y(QQ)); end endgenerate + (* abc9_init = 1'b0 *) $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); // Special signals wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] abc9_ff.init = 1'b0; wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; endmodule @@ -328,11 +329,11 @@ module FDPE (output Q, (* techmap_autopurge *) input C, CE, D, PRE); ); $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ)); end endgenerate + (* abc9_init = 1'b0 *) $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); // Special signals wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] abc9_ff.init = 1'b0; wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; endmodule module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE); @@ -366,11 +367,11 @@ module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE); ); $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE), .Y(QQ)); end endgenerate + (* abc9_init = 1'b0 *) $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); // Special signals wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] abc9_ff.init = 1'b0; wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; endmodule `endif diff --git a/tests/techmap/iopadmap.ys b/tests/techmap/iopadmap.ys index c058d1607..0bcc71cce 100644 --- a/tests/techmap/iopadmap.ys +++ b/tests/techmap/iopadmap.ys @@ -120,3 +120,40 @@ select -assert-count 1 g/t:iobuf select -assert-count 1 h/t:ibuf select -assert-count 1 h/t:iobuf select -assert-count 1 h/t:obuf + + +# Check that \init attributes get moved from output buffer +# to buffer input +design -reset +read_verilog << EOT +module obuf (input i, (* iopad_external_pin *) output o); endmodule +module obuft (input i, input oe, (* iopad_external_pin *) output o); endmodule +module iobuf (input i, input oe, output o, (* iopad_external_pin *) inout io); endmodule +module sub(input i, output o); endmodule + +module a(input i, (* init=1'b1 *) output o); +sub s(.i(i), .o(o)); +endmodule + +module b(input [1:0] i, oe, (* init=2'b1x *) output [1:0] o); +wire [1:0] w; +sub s1(.i(i[0]), .o(w[0])); +sub s2(.i(i[1]), .o(w[1])); +assign o = oe ? w : 2'bz; +endmodule + +module c(input i, oe, (* init=2'b00 *) inout io, output o1, o2); +assign io = oe ? i : 1'bz; +assign {o1,o2} = {io,io}; +endmodule +EOT +opt_clean +tribuf +simplemap +iopadmap -bits -outpad obuf i:o -toutpad obuft oe:i:o -tinoutpad iobuf oe:o:i:io +select -assert-count 1 a/c:s %co a/a:init=1'b1 %i +select -assert-count 1 a/a:init +select -assert-count 1 b/c:s* %co %a b/a:init=2'b1x %i +select -assert-count 1 b/a:init +select -assert-count 1 c/t:iobuf %co c/a:init=2'b00 %i +select -assert-count 1 c/a:init |