I have a signal which needs to be driven/sampled from testbench. I have to drive the signal with respect to negedge of clock and sample it w.r.t posedge.
I have written follwoing code which is working fine but i would like to know whether it is a good coding style or not. (I didn’t negedge/posedge together because most of the driver code need to be driven w.r.t negedge)
It’s OK to have the same signal in two different clocking blocks, but use input to only allow sampling the signal, and output to only allow driving the signal in each respective clocking block.
Also, do not use #0 for input sampling, use #1step or don’t specify a default at all. #1step is the implicit default and gives you the sampled value at the end of the last timestep.
On detecting Reset High on posedge of clock , the FSM enters RESET state and de-asserts TxReady ( Active High signal ) either combinationally ( +define+B in below code ) OR sequentially ( +define+NBA in below code )
On detecting Reset Low on posedge of clock , the FSM enters TXWAIT state
I want to check inside the Monitor that on Entering RESET state the signal TxReady is low , else an Error would be reported
interface INTF ( input clk , input reset );
logic TxReady , TxValid ;
clocking cb_sample @(posedge clk );
default input #0 ;
// Added Purposely to Check Updated Value on posedge of clk and Not b4 posedge
input TxReady ; // I want a checker on this !!
endclocking
modport tb ( clocking cb_sample ) ;
endinterface
module FSM ( INTF i1 ) ;
parameter RESET = 0 , TXWAIT = 1 , SEND_SYNC = 2 ;
reg [1:0] ps , ns ;
always @ ( posedge i1.clk )
begin
if ( i1.reset )
begin
ps <= RESET ;
`ifdef NBA // "NON_BLOCKING_ASSIGNEMNT"
i1.TxReady <= 0 ; // De-assert TxReady
`endif
end
else
begin
ps <= ns ;
end
end
// Output TxReady Combinational Logic
`ifdef B // "B"locking assignment to Tx_Ready
always @ ( ps )
begin
case(ps)
RESET:begin
i1.TxReady = 0 ; // De-assert TxReady
end
endcase
end
`endif
endmodule
Inside the TOP FILE ::
bit CLK = 0 ;
bit RST = 0 ;
INTF intf ( .clk(CLK) , .reset(RST) ) ;
FSM fsm ( .i1(intf) ) ;
typedef enum bit [2:0] {
DEFAULT = 3'd0 ,
RESET_TX = 3'b001,
TX_WAIT = 3'b010,
SEND_SYNC = 3'b011
.....
} tx_device_state_e;
tx_device_state_e Tx_Dev_State ;
initial
begin
fork
begin
forever
#5 CLK = ~CLK ;
end
begin
#50 ;
$finish();
end
join
end
initial begin
#7 RST = 1 ;
#10 RST = 0 ;
end
initial
begin
forever @ ( intf.cb_sample )
case ( Tx_Dev_State )
DEFAULT:begin
TX_WAIT_FOR_RESET_HIGH();
end
RESET_TX:begin
TX_WAIT_FOR_RESET_LOW();
end
endcase
end
task TX_WAIT_FOR_RESET_HIGH();
$display($time ," XXXXX Inside task XXXX ");
fork
begin
wait( RST == 1 );
if ( intf.cb_sample.TxReady == 0 )
begin
$display(" XXXXX IT WORKS !!! XXXXX ");
end
else if ( intf.cb_sample.TxReady == 1 )
begin
$display(" XXXXX ERROR XXXXX "); // An uvm_error would be flashed here
Tx_Dev_State = RESET_TX ;
end
end
join
endtask
Here is the Output I get ::
@5 XXXXX Inside task XXXX
@15 XXXXX Inside task XXXX
XXXXX IT WORKS !!! XXXXX // Got what I wanted , but is it a Right way to Code ??
@25 XXXXX Inside task XXXX
LRM 14.4 Says :: Inputs with explicit #0 skew shall be sampled at the same time as their corresponding clocking event, but to avoid races, they are sampled in the Observed region
So in the Observed Region the Value of TxReady would always be Sampled 0
( either due to Blocking Assignment in Active Region OR NBA Region due to +define+NBA )
It’s OK to have the same signal in two different clocking blocks, but use input to only allow sampling the signal, and output to only allow driving the signal in each respective clocking block.
Also, do not use #0 for input sampling, use #1step or don’t specify a default at all. #1step is the implicit default and gives you the sampled value at the end of the last timestep.
Dave Rich
Mentor Graphics
Hi Dave,
Sorry if this question is too “basic”.
When you refer to “input”/“output”, do you mean the wire name or do you mean the skew sampling spec? I think you mean Example 2 below, please confirm.