verific: Improve logic generated for SVA value change expressions

The previously generated logic assumed an unconstrained past value in
the initial state and did not handle 'x values. While the current formal
verification flow uses 2-valued logic, SVA value change expressions
require a past value of 'x during the initial state to behave in the
expected way (i.e. to consider both an initial 0 and an initial 1 as
$changed and an initial 1 as $rose and an initial 0 as $fell).

This patch now generates logic that at the same time

	a) provides the expected behavior in a 2-valued logic setting, not
	   depending on any dont-care optimizations, and

	b) properly handles 'x values in yosys simulation
This commit is contained in:
Jannis Harder 2022-05-09 15:04:01 +02:00
parent 58b23954e8
commit a855d62b42
8 changed files with 121 additions and 11 deletions

View File

@ -1557,17 +1557,25 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
SigSpec sig_d = net_map_at(inst->GetInput1());
SigSpec sig_o = net_map_at(inst->GetOutput());
SigSpec sig_q = module->addWire(new_verific_id(inst));
SigSpec sig_dx = module->addWire(new_verific_id(inst), 2);
SigSpec sig_qx = module->addWire(new_verific_id(inst), 2);
if (verific_verbose) {
log(" NEX with A=%s, B=0, Y=%s.\n",
log_signal(sig_d), log_signal(sig_dx[0]));
log(" EQX with A=%s, B=1, Y=%s.\n",
log_signal(sig_d), log_signal(sig_dx[1]));
log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
log(" XNOR with A=%s, B=%s, Y=%s.\n",
log_signal(sig_d), log_signal(sig_q), log_signal(sig_o));
log_signal(sig_dx), log_signal(sig_qx), log_signal(clocking.clock_sig));
log(" EQ with A=%s, B=%s, Y=%s.\n",
log_signal(sig_dx), log_signal(sig_qx), log_signal(sig_o));
}
clocking.addDff(new_verific_id(inst), sig_d, sig_q);
module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o);
module->addNex(new_verific_id(inst), sig_d, State::S0, sig_dx[0]);
module->addEqx(new_verific_id(inst), sig_d, State::S1, sig_dx[1]);
clocking.addDff(new_verific_id(inst), sig_dx, sig_qx, Const(1, 2));
module->addEq(new_verific_id(inst), sig_dx, sig_qx, sig_o);
if (!mode_keep)
continue;
@ -1601,13 +1609,20 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
SigBit sig_d = net_map_at(inst->GetInput1());
SigBit sig_o = net_map_at(inst->GetOutput());
SigBit sig_q = module->addWire(new_verific_id(inst));
SigBit sig_d_no_x = module->addWire(new_verific_id(inst));
if (verific_verbose)
if (verific_verbose) {
log(" EQX with A=%s, B=%d, Y=%s.\n",
log_signal(sig_d), inst->Type() == PRIM_SVA_ROSE, log_signal(sig_d_no_x));
log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
log_signal(sig_d_no_x), log_signal(sig_q), log_signal(clocking.clock_sig));
log(" EQ with A={%s, %s}, B={0, 1}, Y=%s.\n",
log_signal(sig_q), log_signal(sig_d_no_x), log_signal(sig_o));
}
clocking.addDff(new_verific_id(inst), sig_d, sig_q);
module->addEq(new_verific_id(inst), {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o);
module->addEqx(new_verific_id(inst), sig_d, inst->Type() == PRIM_SVA_ROSE ? State::S1 : State::S0, sig_d_no_x);
clocking.addDff(new_verific_id(inst), sig_d_no_x, sig_q, State::S0);
module->addEq(new_verific_id(inst), {sig_q, sig_d_no_x}, Const(1, 2), sig_o);
if (!mode_keep)
continue;

View File

@ -3,5 +3,6 @@
/*_pass
/*_fail
/*.ok
/*.fst
/vhdlpsl[0-9][0-9]
/vhdlpsl[0-9][0-9].sby

View File

@ -10,4 +10,5 @@ clean:
rm -rf $(addsuffix .ok,$(TESTS)) $(addsuffix .sby,$(TESTS)) $(TESTS)
rm -rf $(addsuffix _pass.sby,$(TESTS)) $(addsuffix _pass,$(TESTS))
rm -rf $(addsuffix _fail.sby,$(TESTS)) $(addsuffix _fail,$(TESTS))
rm -rf $(addsuffix .fst,$(TESTS))

View File

@ -57,7 +57,9 @@ generate_sby() {
fi
}
if [ -f $prefix.sv ]; then
if [ -f $prefix.ys ]; then
$PWD/../../yosys -q -e "Assert .* failed." -s $prefix.ys
elif [ -f $prefix.sv ]; then
generate_sby pass > ${prefix}_pass.sby
generate_sby fail > ${prefix}_fail.sby
sby --yosys $PWD/../../yosys -f ${prefix}_pass.sby

View File

@ -0,0 +1,17 @@
module top (
input clk,
input a, b
);
default clocking @(posedge clk); endclocking
assert property (
$changed(b)
);
`ifndef FAIL
assume property (
b !== 'x ##1 $changed(b)
);
`endif
endmodule

View File

@ -0,0 +1,20 @@
module top (
input clk,
input a, b
);
default clocking @(posedge clk); endclocking
wire a_copy;
assign a_copy = a;
assert property (
$rose(a) |-> b
);
`ifndef FAIL
assume property (
$rose(a_copy) |-> b
);
`endif
endmodule

View File

@ -0,0 +1,51 @@
module top (
input clk
);
reg [7:0] counter = 0;
reg a = 0;
reg b = 1;
reg c;
wire a_fell; assign a_fell = $fell(a, @(posedge clk));
wire a_rose; assign a_rose = $rose(a, @(posedge clk));
wire a_stable; assign a_stable = $stable(a, @(posedge clk));
wire b_fell; assign b_fell = $fell(b, @(posedge clk));
wire b_rose; assign b_rose = $rose(b, @(posedge clk));
wire b_stable; assign b_stable = $stable(b, @(posedge clk));
wire c_fell; assign c_fell = $fell(c, @(posedge clk));
wire c_rose; assign c_rose = $rose(c, @(posedge clk));
wire c_stable; assign c_stable = $stable(c, @(posedge clk));
always @(posedge clk) begin
counter <= counter + 1;
case (counter)
0: begin
assert property ( $fell(a) && !$rose(a) && !$stable(a));
assert property (!$fell(b) && $rose(b) && !$stable(b));
assert property (!$fell(c) && !$rose(c) && $stable(c));
a <= 1; b <= 1; c <= 1;
end
1: begin a <= 0; b <= 1; c <= 'x; end
2: begin
assert property ( $fell(a) && !$rose(a) && !$stable(a));
assert property (!$fell(b) && !$rose(b) && $stable(b));
assert property (!$fell(c) && !$rose(c) && !$stable(c));
a <= 0; b <= 0; c <= 0;
end
3: begin a <= 0; b <= 1; c <= 'x; end
4: begin
assert property (!$fell(a) && !$rose(a) && $stable(a));
assert property (!$fell(b) && $rose(b) && !$stable(b));
assert property (!$fell(c) && !$rose(c) && !$stable(c));
a <= 'x; b <= 'x; c <= 'x;
end
5: begin a <= 0; b <= 1; c <= 'x; counter <= 0; end
endcase;
end
endmodule

View File

@ -0,0 +1,3 @@
read -sv sva_value_change_sim.sv
hierarchy -top top
sim -clock clk -fst sva_value_change_sim.fst