How to pass Induction in SymbiYosys?

821 views Asked by At

I am very new to formal verification and I started my formal verification with SymbiYosys. I had written some code in System Verilog for learning formal verification, I was able to pass BMC and cover for the code but it is failing (UNKNOWN sate) for induction.

I don't have much understanding of formal proving but my current understanding of induction proving is: my design will start in the future time in the assertion sate and all my register will be set in some state that would have triggered my assertion and from that state SymbiYosys engine will try to find a valid state in the reverse timestep which would have made to the assertion sate. Maybe my understanding is wrong.

My design passes assertions and also covers but in induction it sets the values RCON registers to zero but RCON registers are initialized by rcon.mem file using $readmemh("box.mem",mem); then if this register initialization can be overridden by in induction prove then how do I write my code that will pass induction. What is the best method to initalize a register in RTL.

Please Help on this, I have my mcve .sv code, .sby configuration, .mem file and .vcd gtkwave screenshot attached.

my error logfile is also attached

test_mcve_prove/logfile.txt

SBY 21:27:37 [test_mcve_bmc] Removing directory 'test_mcve_bmc'.
SBY 21:27:39 [test_mcve_cover] Removing directory 'test_mcve_cover'.
SBY 21:27:47 [test_mcve_prove] Removing directory 'test_mcve_prove'.
SBY 21:27:47 [test_mcve_prove] Copy 'test_mcve.sv' to 'test_mcve_prove/src/test_mcve.sv'.
SBY 21:27:47 [test_mcve_prove] Copy 'rcon.mem' to 'test_mcve_prove/src/rcon.mem'.
SBY 21:27:47 [test_mcve_prove] engine_0: smtbmc
SBY 21:27:47 [test_mcve_prove] base: starting process "cd test_mcve_prove/src; yosys -ql ../model/design.log ../model/design.ys"
SBY 21:27:47 [test_mcve_prove] base: finished (returncode=0)
SBY 21:27:47 [test_mcve_prove] smt2: starting process "cd test_mcve_prove/model; yosys -ql design_smt2.log design_smt2.ys"
SBY 21:27:47 [test_mcve_prove] smt2: finished (returncode=0)
SBY 21:27:47 [test_mcve_prove] engine_0.basecase: starting process "cd test_mcve_prove; yosys-smtbmc --presat --unroll --noprogress -t 4  --append 0 --dump-vcd engine_0/trace.vcd --dump-vlogtb engine_0/trace_tb.v --dump-smtc engine_0/trace.smtc model/design_smt2.smt2"
SBY 21:27:47 [test_mcve_prove] engine_0.induction: starting process "cd test_mcve_prove; yosys-smtbmc --presat --unroll -i --noprogress -t 4  --append 0 --dump-vcd engine_0/trace_induct.vcd --dump-vlogtb engine_0/trace_induct_tb.v --dump-smtc engine_0/trace_induct.smtc model/design_smt2.smt2"
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: ##   0:00:00  Solver: yices
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Solver: yices
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: ##   0:00:00  Checking assumptions in step 0..
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: ##   0:00:00  Checking assertions in step 0..
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Trying induction in step 4..
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: ##   0:00:00  Checking assumptions in step 1..
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: ##   0:00:00  Checking assertions in step 1..
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Trying induction in step 3..
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: ##   0:00:00  Checking assumptions in step 2..
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: ##   0:00:00  Checking assertions in step 2..
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Trying induction in step 2..
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Trying induction in step 1..
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: ##   0:00:00  Checking assumptions in step 3..
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: ##   0:00:00  Checking assertions in step 3..
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Trying induction in step 0..
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Temporal induction failed!
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Assert failed in test_mcve: test_mcve.sv:111.46-112.39
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Writing trace to VCD file: engine_0/trace_induct.vcd
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: ##   0:00:00  Status: passed
SBY 21:27:48 [test_mcve_prove] engine_0.basecase: finished (returncode=0)
SBY 21:27:48 [test_mcve_prove] engine_0: Status returned by engine for basecase: pass
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Writing trace to Verilog testbench: engine_0/trace_induct_tb.v
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Writing trace to constraints file: engine_0/trace_induct.smtc
SBY 21:27:48 [test_mcve_prove] engine_0.induction: ##   0:00:00  Status: failed
SBY 21:27:48 [test_mcve_prove] engine_0.induction: finished (returncode=1)
SBY 21:27:48 [test_mcve_prove] engine_0: Status returned by engine for induction: FAIL
SBY 21:27:48 [test_mcve_prove] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:01 (1)
SBY 21:27:48 [test_mcve_prove] summary: Elapsed process time [H:MM:SS (secs)]: 0:00:01 (1)
SBY 21:27:48 [test_mcve_prove] summary: engine_0 (smtbmc) returned pass for basecase
SBY 21:27:48 [test_mcve_prove] summary: engine_0 (smtbmc) returned FAIL for induction
SBY 21:27:48 [test_mcve_prove] DONE (UNKNOWN, rc=4)

test_mcve.sv

`default_nettype    none

module test_mcve(ext_Clk,ext_Resetn,ext_Start,ext_round,ext_next_round,xor_in_if);
//parameter for module

parameter WIDTH = 8;
parameter NUMBER_OF_ROUNDS = 10;



//external interface signals
input ext_Clk,ext_Resetn,ext_Start; //clk , reset, start
input  [3:0] ext_round;
output logic [3:0] ext_next_round;
output logic [WIDTH-1:0] xor_in_if;

//input round register
logic [3:0] round;
logic [1:0]index_sel;

//Round constant 8 bits
reg [WIDTH-1:0]RCON[(NUMBER_OF_ROUNDS-1):0] /* synthesis ram_init_file = "rcon.mif" */; 
initial begin
    $readmemh("rcon.mem", RCON);
end


//state machine states
typedef enum logic[1:0] {Idle_s,Comput_s} state_t;
state_t state,next_state;

//###################################################### state register
logic reset;
assign reset = !ext_Resetn;
always_ff@(posedge ext_Clk,posedge reset) begin
    if(reset) state <= Idle_s;
    else      state <= next_state;
end

//###################################################### next state logic
always_comb begin
    case (state)
        Idle_s: if ((ext_Start == 1)&&(ext_round == ext_next_round)&&(ext_round<NUMBER_OF_ROUNDS)&&(reset == 0)) next_state = Comput_s;
                else next_state = Idle_s;

        Comput_s: if (index_sel==3) next_state = Idle_s;
                else next_state = Comput_s;

        default: next_state = Idle_s;

    endcase
end
//####################################################### output logic



logic [WIDTH-1:0] temp_rcon;
assign xor_in_if = (index_sel == 3)?temp_rcon:0;



//next round output logic
always@(posedge ext_Clk,posedge reset)begin
    if(reset) ext_next_round<=0;
    else if(index_sel==3) ext_next_round<=ext_next_round+1;
end



//output logic
always@(posedge ext_Clk) begin
    case (state)
        Idle_s: begin
            index_sel<=0;
            if(ext_round<10)
                round <= ext_round;
            else
                round <= NUMBER_OF_ROUNDS;
        end
        Comput_s: begin
            index_sel<=index_sel+1;
            temp_rcon<=RCON[round];
        end
        default:begin
            
        end
    endcase
end

//#########################################################
//################### FORMAL VERIFICATION #################
//#########################################################
`ifdef FORMAL
  //Using Immediate assertion

  
logic verf_valid;

initial begin
    assume(verf_valid==0);
    assume(ext_Resetn == 0);
end
always @(posedge(ext_Clk))begin
    verf_valid<=1;
end

// verification
always@(posedge(ext_Clk)) begin
    if((verf_valid==1) && (ext_Resetn != 0))begin
        if((round==0)&&(index_sel == 3))begin
            assert(xor_in_if == 8'h01);
            cover(xor_in_if == 8'h01);
        end
         if((round==1)&&(index_sel == 3))begin
            assert(xor_in_if == 8'h02);
            cover(xor_in_if == 8'h02);
        end
        if((round==2)&&(index_sel == 3))begin
            assert(xor_in_if == 8'h04);
            cover(xor_in_if == 8'h04);
        end
        if((round==3)&&(index_sel == 3))begin
            assert(xor_in_if == 8'h08);
            cover(xor_in_if == 8'h08);
        end
        if((round==4)&&(index_sel == 3))begin
            assert(xor_in_if == 8'h10);
            cover(xor_in_if == 8'h10);
        end
        if((round==5)&&(index_sel == 3))begin
            assert(xor_in_if == 8'h20);
            cover(xor_in_if == 8'h20);
        end
        if((round==6)&&(index_sel == 3))begin
            assert(xor_in_if == 8'h40);
            cover(xor_in_if == 8'h40);
        end
        if((round==7)&&(index_sel == 3))begin
            assert(xor_in_if == 8'h80);
            cover(xor_in_if == 8'h80);
        end
        if((round==8)&&(index_sel == 3))begin
            assert(xor_in_if == 8'h1b);
            cover(xor_in_if == 8'h1b);
        end
        if((round==9)&&(index_sel == 3))begin
            assert(xor_in_if == 8'h36);
            cover(xor_in_if == 8'h36);
        end
          
    end
 end

`endif

endmodule 

test_mcve.sby

[tasks]
bmc d_12
cover d_120
prove d_4

[options]
bmc:mode bmc
cover:mode cover
prove:mode prove
d_120:depth 120
d_12:depth 12
d_4:depth 4

[engines]
smtbmc

[script]
read -formal -sv test_mcve.sv
prep -top test_mcve

[files]
test_mcve.sv
rcon.mem

rcon.mem

01 02 04 08 10 
20 40 80 1B 36

trace_induct.vcd screenshot enter image description here

1

There are 1 answers

0
Shashidhar B On

I was going through the slides from Clifford wolf(link is below), and found a slide-29 where he had illustrated an example memcmp.v to demonstrate induction proving for two memmory modules by using .smtc file in his .sby file. Then I used the same method to initialize my RCON register, then my induction proving passed(my .sby and .smtc files are attached)

I do not know whether using .smtc file to initialize my registers is a good practice for induction prove. If you guys have better answer please suggest me.

Link to Clifford wolf's slides (Check slide-29)

My initialize_RCON.smtc file (I had just copied the assume statements from cover directory engin0 .smtc file, which will be created if we had covered statements for memory initialization and all the cover statement passes. Same is copied to assert section):

initial
assume (= (select [RCON] #b0000) #b00000001)
assume (= (select [RCON] #b1000) #b00011011)
assume (= (select [RCON] #b0001) #b00000010)
assume (= (select [RCON] #b0010) #b00000100)
assume (= (select [RCON] #b0011) #b00001000)
assume (= (select [RCON] #b0100) #b00010000)
assume (= (select [RCON] #b0101) #b00100000)
assume (= (select [RCON] #b0110) #b01000000)
assume (= (select [RCON] #b0111) #b10000000)
assume (= (select [RCON] #b1001) #b00110110)

My test_mcve.sby

[tasks]
bmc d_12
cover d_120
prove d_12 smtc_prove

[options]
bmc:mode bmc
cover:mode cover
prove:mode prove
d_120:depth 120
d_12:depth 12
smtc_prove:smtc initialize_RCON.smtc

[engines]
smtbmc

[script]
read -formal -sv test_mcve.sv
prep -top test_mcve

[files]
initialize_RCON.smtc
test_mcve.sv
rcon.mem

To run induction test only, I use prove task as shown below:

sby -f test_mcve.sby prove