Merge remote-tracking branch 'origin/master' into xaig_dff

This commit is contained in:
Eddie Hung 2019-11-25 12:42:09 -08:00
commit d087024caf
10 changed files with 83 additions and 18 deletions

View File

@ -343,6 +343,13 @@ Verilog Attributes and non-standard features
- The ``clkbuf_sink`` attribute can be set on an input port of a module to
request clock buffer insertion by the ``clkbufmap`` pass.
- The ``clkbuf_inv`` attribute can be set on an output port of a module
with the value set to the name of an input port of that module. When
the ``clkbufmap`` would otherwise insert a clock buffer on this output,
it will instead try inserting the clock buffer on the input port (this
is used to implement clock inverter cells that clock buffer insertion
will "see through").
- The ``clkbuf_inhibit`` is the default attribute to set on a wire to prevent
automatic clock buffer insertion by ``clkbufmap``. This behaviour can be
overridden by providing a custom selection to ``clkbufmap``.

View File

@ -115,6 +115,8 @@ struct ClkbufmapPass : public Pass {
// Cell type, port name, bit index.
pool<pair<IdString, pair<IdString, int>>> sink_ports;
pool<pair<IdString, pair<IdString, int>>> buf_ports;
dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_out;
dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_in;
// Process submodules before module using them.
std::vector<Module *> modules_sorted;
@ -133,6 +135,14 @@ struct ClkbufmapPass : public Pass {
if (wire->get_bool_attribute("\\clkbuf_sink"))
for (int i = 0; i < GetSize(wire); i++)
sink_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
auto it = wire->attributes.find("\\clkbuf_inv");
if (it != wire->attributes.end()) {
IdString in_name = RTLIL::escape_id(it->second.decode_string());
for (int i = 0; i < GetSize(wire); i++) {
inv_ports_out[make_pair(module->name, make_pair(wire->name, i))] = make_pair(in_name, i);
inv_ports_in[make_pair(module->name, make_pair(in_name, i))] = make_pair(wire->name, i);
}
}
}
continue;
}
@ -157,6 +167,37 @@ struct ClkbufmapPass : public Pass {
if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i))))
buf_wire_bits.insert(sigmap(port.second[i]));
// Third, propagate tags through inverters.
bool retry = true;
while (retry) {
retry = false;
for (auto cell : module->cells())
for (auto port : cell->connections())
for (int i = 0; i < port.second.size(); i++) {
auto it = inv_ports_out.find(make_pair(cell->type, make_pair(port.first, i)));
auto bit = sigmap(port.second[i]);
// If output of an inverter is connected to a sink, mark it as buffered,
// and request a buffer on the inverter's input instead.
if (it != inv_ports_out.end() && !buf_wire_bits.count(bit) && sink_wire_bits.count(bit)) {
buf_wire_bits.insert(bit);
auto other_bit = sigmap(cell->getPort(it->second.first)[it->second.second]);
sink_wire_bits.insert(other_bit);
retry = true;
}
// If input of an inverter is marked as already-buffered,
// mark its output already-buffered as well.
auto it2 = inv_ports_in.find(make_pair(cell->type, make_pair(port.first, i)));
if (it2 != inv_ports_in.end() && buf_wire_bits.count(bit)) {
auto other_bit = sigmap(cell->getPort(it2->second.first)[it2->second.second]);
if (!buf_wire_bits.count(other_bit)) {
buf_wire_bits.insert(other_bit);
retry = true;
}
}
}
};
// Collect all driven bits.
for (auto cell : module->cells())
for (auto port : cell->connections())

View File

@ -194,8 +194,6 @@ struct SynthCoolrunner2Pass : public ScriptPass
if (!json_file.empty() || help_mode)
run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
}
log_pop();
}
} SynthCoolrunner2Pass;

View File

@ -126,7 +126,11 @@ endmodule
// assign O = IO, IO = T ? 1'bz : I;
// endmodule
module INV(output O, input I);
module INV(
(* clkbuf_inv = "I" *)
output O,
input I
);
assign O = !I;
endmodule

View File

@ -56,8 +56,12 @@ module \$lut (A, Y);
generate
if (WIDTH == 1) begin
LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]));
if (P_LUT == 2'b01) begin
INV _TECHMAP_REPLACE_ (.O(Y), .I(A[0]));
end else begin
LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]));
end
end else
if (WIDTH == 2) begin
LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),

View File

@ -20,9 +20,9 @@ design -load postopt # load the post-opt design (otherwise equiv_opt loads the p
cd adffn # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
select -assert-count 1 t:FDCE
select -assert-count 1 t:LUT1
select -assert-count 1 t:INV
select -assert-none t:BUFG t:FDCE t:LUT1 %% t:* %D
select -assert-none t:BUFG t:FDCE t:INV %% t:* %D
design -load read

View File

@ -8,7 +8,7 @@ cd top # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
select -assert-count 8 t:FDCE
select -assert-count 1 t:LUT1
select -assert-count 1 t:INV
select -assert-count 7 t:MUXCY
select -assert-count 8 t:XORCY
select -assert-none t:BUFG t:FDCE t:LUT1 t:MUXCY t:XORCY %% t:* %D
select -assert-none t:BUFG t:FDCE t:INV t:MUXCY t:XORCY %% t:* %D

View File

@ -18,9 +18,9 @@ equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx # equivalen
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd latchn # Constrain all select calls below inside the top module
select -assert-count 1 t:LDCE
select -assert-count 1 t:LUT1
select -assert-count 1 t:INV
select -assert-none t:LDCE t:LUT1 %% t:* %D
select -assert-none t:LDCE t:INV %% t:* %D
design -load read

View File

@ -5,7 +5,7 @@ equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 1 t:LUT1
select -assert-count 1 t:INV
select -assert-count 6 t:LUT2
select -assert-count 2 t:LUT4
select -assert-none t:LUT1 t:LUT2 t:LUT4 %% t:* %D
select -assert-none t:INV t:LUT2 t:LUT4 %% t:* %D

View File

@ -4,6 +4,7 @@ module dff ((* clkbuf_sink *) input clk, input d, output q); endmodule
module dffe ((* clkbuf_sink *) input c, input d, e, output q); endmodule
module latch (input e, d, output q); endmodule
module clkgen (output o); endmodule
module inv ((* clkbuf_inv = "i" *) output o, input i); endmodule
module top(input clk1, clk2, clk3, d, e, output [4:0] q);
wire clk4, clk5, clk6;
@ -17,12 +18,18 @@ dff s6 (.clk(clk6), .d(d), .q(q[4]));
endmodule
module sub(output sclk4, output sclk5, output sclk6, input sd, output sq);
wire sclk7, sclk8, sclk9;
wire siq;
wire tmp;
clkgen s7(.o(sclk4));
clkgen s8(.o(sclk5));
clkgen s9(.o(tmp));
clkbuf s10(.i(tmp), .o(sclk6));
dff s11(.clk(sclk4), .d(sd), .q(sq));
clkbuf s10(.i(tmp), .o(sclk7));
dff s11(.clk(sclk4), .d(sd), .q(siq));
inv s15(.i(sclk7), .o(sclk6));
clkgen s12(.o(sclk8));
inv s13(.o(sclk9), .i(sclk8));
dff s14(.clk(sclk9), .d(siq), .q(sq));
endmodule
EOT
@ -34,7 +41,7 @@ design -save ref
design -load ref
clkbufmap -buf clkbuf o:i
select -assert-count 3 top/t:clkbuf
select -assert-count 2 sub/t:clkbuf
select -assert-count 3 sub/t:clkbuf
select -set clk1 w:clk1 %a %co t:clkbuf %i # Find 'clk1' fanouts that are 'clkbuf'
select -assert-count 1 @clk1 # Check there is one such fanout
select -assert-count 1 @clk1 %x:+[o] %co c:s* %i # Check that the 'o' of that clkbuf drives one fanout
@ -51,6 +58,10 @@ select -set sclk4 w:sclk4 %a %ci t:clkbuf %i
select -assert-count 1 @sclk4
select -assert-count 1 @sclk4 %x:+[o] %co c:s11 %i
select -assert-count 1 @sclk4 %x:+[i] %ci c:s7 %i
select -set sclk8 w:sclk8 %a %ci t:clkbuf %i
select -assert-count 1 @sclk8
select -assert-count 1 @sclk8 %x:+[o] %co c:s13 %i
select -assert-count 1 @sclk8 %x:+[i] %ci c:s12 %i
# ----------------------
@ -72,7 +83,7 @@ setattr -set clkbuf_inhibit 1 w:clk1
setattr -set buffer_type "bufg" w:clk2
clkbufmap -buf clkbuf o:i w:* a:buffer_type=none a:buffer_type=bufr %u %d
select -assert-count 3 top/t:clkbuf
select -assert-count 2 sub/t:clkbuf
select -assert-count 3 sub/t:clkbuf
select -set clk1 w:clk1 %a %co t:clkbuf %i # Find 'clk1' fanouts that are 'clkbuf'
select -assert-count 1 @clk1 # Check there is one such fanout
select -assert-count 1 @clk1 %x:+[o] %co c:s* %i # Check that the 'o' of that clkbuf drives one fanout
@ -93,4 +104,4 @@ clkbufmap -buf clkbuf o:i w:* a:buffer_type=none a:buffer_type=bufr %u %d
select -assert-count 0 w:clk1 %a %co t:clkbuf %i
select -assert-count 0 w:clk2 %a %co t:clkbuf %i
select -assert-count 0 top/t:clkbuf
select -assert-count 1 sub/t:clkbuf
select -assert-count 2 sub/t:clkbuf