SystemVerilog has a nice implication constraint feature to guard constraint expressions on their applicability. Last week during our SystemVerilog + methodology workshop one of the attendees faced an interesting issue. She was creating a min-VIP for APB as part of our SystemVerilog 10-day workshop (See details at: http://www.cvcblr.com/trng_profiles/CVC_VSV_WK_profile.pdf ).
She wrote a APB scenario code that was intended to create a sequence of transactions with varying address, kind etc. Here is a code snippet:
constraint cst_xactn_kind{
if(this.scenario_kind == this.sc_id)
this.length == 10;
foreach (items[i])
{
(i==0) -> items[i].apb_op_kind == APB_WR;items[i].addr == 'b01; items[i].wdata == 'd11;
(i==1) -> items[i].apb_op_kind == APB_WR;items[i].addr == 'b11; items[i].wdata == 'd12;
}
}
Spot anything wrong in the above code? Perhaps not for the unsuspecting, bare eyes. Code intention: Keep the:
0th transaction KIND == WRITE, address == 01, data == 11;
1st transaction KIND == WRITE, address == 3, data == 12;
Read again the code – it seems to imply just that, isn’t it? Let’s run it.
Here is what Questa says:
###########################################################################
# WELCOME !!!
# APB PROJECT USING VMM
# DONE BY PRIYA @ CVC
# DATE:21stOctober2009
############################################################################
# Normal[NOTE] on APB_PROGRAM(0) at 0:
# APB PROJECT: Start of APB Random test!
# ****************************************************************************
# Normal[NOTE] on APB_ENV(0) at 0.00 ns:
# APB PROJECT: Sim shall run for 10 number of transactions
# Normal[NOTE] on APB_ENV(0) at 0.00 ns:
# Reset!!!!!!!!!
# Normal[NOTE] on APB_ENV(0) at 230.00 ns:
# Reset Release!
# ****************************************************************************
# *FATAL*[FAILURE] on APB Generator Scenario Generator(APB_GENERATOR) at 730.00 ns:
# Cannot randomize scenario descriptor #0
Puzzled? What is wrong? Review by the code author herself few times didn’t reveal anything wrong (bias towards own code?).
Seek expert assistance.. Questa has a simple flag to bring up solver debugger as: vsim –solvefaildebug Let’s try that now..
# ../tb_src_scenario/apb_scenario_gen.sv(1): randomize() failed due to conflicts between the following constraints:
# ../tb_src_scenario/apb_scenario_gen.sv(25): the_scenario.cst_xactn_kind { (the_scenario.items[0].addr == 32'h00000001); }
# ../tb_src_scenario/apb_scenario_gen.sv(1): the_scenario.repetition { (the_scenario.repeated == 32'h00000000); }
# ../tb_src_scenario/apb_scenario_gen.sv(25): the_scenario.cst_xactn_kind { (the_scenario.items[0].apb_op_kind == APB_WR); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[0].addr == 32'h00000003); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[0].wdata == 32'h0000000c); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[1].apb_op_kind == APB_WR); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[1].addr == 32'h00000003); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[1].wdata == 32'h0000000c); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[2].addr == 32'h00000003); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[2].wdata == 32'h0000000c); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[3].addr == 32'h00000003); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[3].wdata == 32'h0000000c); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[4].addr == 32'h00000003); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[4].wdata == 32'h0000000c); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[5].addr == 32'h00000003); }
# ../tb_src_scenario/apb_scenario_gen.sv(26): the_scenario.cst_xactn_kind { (the_scenario.items[5].wdata == 32'h0000000c); }
Smell something wrong? Why is the constraint on addr, data getting applied across scenario items 2,3,4,5 etc.? Beyond the 0, 1 that the “implication” supposed to guard it? Relook at constraint code:
(i==0) -> items[i].apb_op_kind == APB_WR;items[i].addr == 'b01; items[i].wdata == 'd11;
Found it? Not yet? The devil lies in details – here in that SEMICOLON “ ; “. A semicolon in Verilog/SV denotes END of a statement and begin of the next one. Hence the effect of “implication” is ENDED with the variable “kind” alone here – thereby it doesn’t affect the addr, data – hence the implication is invisible to them. At line 25, the addr == 1; At line 26, addr == 3; Hence the contradiction!
The fix will be to use && to imply that the guard is applicable to all the 3 variables – kind && addr && data.
Instead of:
(i==0) -> items[i].apb_op_kind == APB_WR;items[i].addr == 'b01; items[i].wdata == 'd11;
Use:
(i==0) –> (items[i].apb_op_kind == APB_WR) && (items[i].addr == 'b01) && (items[i].wdata == 'd11);
Morale of the debug session is: you need to be careful while using implication constraints for more than single variable :-)