Skip to content

dfflibmap: propagate negated next_state to output correctly #5190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions passes/techmap/dfflibmap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -392,9 +392,21 @@ static void find_cell_sr(std::vector<const LibertyAst *> cells, IdString cell_ty
continue;
if (!parse_next_state(cell, ff->find("next_state"), cell_next_pin, cell_next_pol, cell_enable_pin, cell_enable_pol))
continue;
if (!parse_pin(cell, ff->find("preset"), cell_set_pin, cell_set_pol) || cell_set_pol != setpol)

if (!parse_pin(cell, ff->find("preset"), cell_set_pin, cell_set_pol))
continue;
if (!parse_pin(cell, ff->find("clear"), cell_clr_pin, cell_clr_pol))
continue;
if (!cell_next_pol) {
// next_state is negated
// we later propagate this inversion to the output,
// which requires the swap of set and reset
std::swap(cell_set_pin, cell_clr_pin);
std::swap(cell_set_pol, cell_clr_pol);
}
if (cell_set_pol != setpol)
continue;
if (!parse_pin(cell, ff->find("clear"), cell_clr_pin, cell_clr_pol) || cell_clr_pol != clrpol)
if (cell_clr_pol != clrpol)
continue;

std::map<std::string, char> this_cell_ports;
Expand Down Expand Up @@ -432,12 +444,14 @@ static void find_cell_sr(std::vector<const LibertyAst *> cells, IdString cell_ty
for (size_t pos = value.find_first_of("\" \t"); pos != std::string::npos; pos = value.find_first_of("\" \t"))
value.erase(pos, 1);
if (value == ff->args[0]) {
// next_state negation propagated to output
this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q';
if (cell_next_pol)
found_noninv_output = true;
found_output = true;
} else
if (value == ff->args[1]) {
// next_state negation propagated to output
this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q';
if (!cell_next_pol)
found_noninv_output = true;
Expand Down
33 changes: 33 additions & 0 deletions tests/techmap/dfflibmap_dffr_not_next.lib
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
library(test) {
cell (dffr_not_next) {
area : 6;
ff("IQ", "IQN") {
next_state : "!D";
clocked_on : "CLK";
clear : "CLEAR";
preset : "PRESET";
clear_preset_var1 : L;
clear_preset_var2 : L;
}
pin(D) {
direction : input;
}
pin(CLK) {
direction : input;
}
pin(CLEAR) {
direction : input;
}
pin(PRESET) {
direction : input;
}
pin(Q) {
direction: output;
function : "IQ";
}
pin(QN) {
direction: output;
function : "IQN";
}
}
}
28 changes: 28 additions & 0 deletions tests/techmap/dfflibmap_dffsr_not_next.lib
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
library (test_not_next) {
cell (dffsr_not_next) {
area : 1.0;
pin (Q) {
direction : output;
function : "STATE";
}
pin (CLK) {
clock : true;
direction : input;
}
pin (D) {
direction : input;
}
pin (RN) {
direction : input;
}
pin (SN) {
direction : input;
}
ff (STATE,STATEN) {
clear : "!SN";
clocked_on : "CLK";
next_state : "!D";
preset : "!RN";
}
}
}
116 changes: 116 additions & 0 deletions tests/techmap/dfflibmap_formal.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
##################################################################

read_verilog -sv -icells <<EOT

module top(input C, D, E, S, R, output [11:0] Q);

$_DFF_P_ ff0 (.C(C), .D(D), .Q(Q[0]));
$_DFF_PP0_ ff1 (.C(C), .D(D), .R(R), .Q(Q[1]));
$_DFF_PP1_ ff2 (.C(C), .D(D), .R(R), .Q(Q[2]));

// Formal checking of directly instantiated DFFSR doesn't work at the moment
// likely due to an equiv_induct assume bug #5196

// // Workaround for DFFSR bug #5194
// assume property (~R || ~S);
// $_DFFSR_PPP_ ff3 (.C(C), .D(D), .R(R), .S(S), .Q(Q[3]));
// $_DFFSR_NNN_ ff4 (.C(C), .D(D), .R(~R), .S(~S), .Q(Q[4]));

$_DFFE_PP_ ff5 (.C(C), .D(D), .E(E), .Q(Q[5]));

assign Q[11:6] = ~Q[5:0];

endmodule

EOT

proc
opt
read_liberty dfflibmap_dffn_dffe.lib
read_liberty dfflibmap_dffsr_not_next.lib

copy top top_unmapped
dfflibmap -liberty dfflibmap_dffn_dffe.lib -liberty dfflibmap_dffsr_not_next.lib top

async2sync
flatten
opt_clean -purge
equiv_make top top_unmapped equiv
equiv_induct equiv
equiv_status -assert equiv

##################################################################

design -reset
read_verilog -sv -icells <<EOT

module top(input C, D, E, S, R, output [11:0] Q);

$_DFF_P_ ff0 (.C(C), .D(D), .Q(Q[0]));
$_DFF_PP0_ ff1 (.C(C), .D(D), .R(R), .Q(Q[1]));
$_DFF_PP1_ ff2 (.C(C), .D(D), .R(R), .Q(Q[2]));

// Formal checking of directly instantiated DFFSR doesn't work at the moment
// likely due to an equiv_induct assume bug #5196

// // Workaround for DFFSR bug #5194
// assume property (~R || ~S);
// $_DFFSR_PPP_ ff3 (.C(C), .D(D), .R(R), .S(S), .Q(Q[3]));
// $_DFFSR_NNN_ ff4 (.C(C), .D(D), .R(~R), .S(~S), .Q(Q[4]));

$_DFFE_PP_ ff5 (.C(C), .D(D), .E(E), .Q(Q[5]));

assign Q[11:6] = ~Q[5:0];

endmodule

EOT

proc
opt
read_liberty dfflibmap_dffr_not_next.lib

copy top top_unmapped
dfflibmap -liberty dfflibmap_dffr_not_next.lib top

async2sync
flatten
opt_clean -purge
equiv_make top top_unmapped equiv
equiv_induct equiv
equiv_status -assert equiv

##################################################################

design -reset
read_verilog <<EOT

module top(input C, D, E, S, R, output Q);
// DFFSR with priority R over S
always @(posedge C, posedge R, posedge S)
if (R == 1)
Q <= 0;
else if (S == 1)
Q <= 1;
else
Q <= D;

endmodule

EOT

proc
opt
read_liberty dfflibmap_dffn_dffe.lib
read_liberty dfflibmap_dffsr_not_next.lib

copy top top_unmapped
simplemap top
dfflibmap -liberty dfflibmap_dffn_dffe.lib -liberty dfflibmap_dffsr_not_next.lib top

async2sync
flatten
opt_clean -purge
equiv_make top top_unmapped equiv
equiv_induct equiv
equiv_status -assert equiv
Loading