Hi everyone, I am very very new to verification so be gentle. I am wondering how one would go about making this a self-checking testcase, I am sure there are many ways to do it. I am looking for some general / high level advice. I am familiar with writing very basic assert statements and also the concept of a scoreboard, but less experienced with the latter.
We have this transmitter module that is essentially a SERDES that serializes data from a specific register. So all my testcase does is write some test pattern to a register, then I go and look at the output waveform and see that it correctly serialized the data. Everything is in SystemVerilog and the testcases are written as tasks.
I know I am not giving much info here, but I am just looking for general advice on where to start. Should I research scoreboards / monitors and UVM? Should I try writing assert statements?
I really do not see the need for UVM for this simple partition.
SVA, with some support logic, can do a good job at analyzing the loading, serialization, and deserialization processes. As far as test pattern generation, you can use a simple randomization with weighted variables. In fact, this is exactly how I verify my assertions, as shown below.
// a, b are my variables
initial begin
bit v_a, v_b, v_err;
repeat (200) begin
@(posedge clk);
if (!randomize(v_a, v_b, v_err) with {
v_a dist {1'b1 := 1, 1'b0 := 1};
v_b dist {1'b1 := 1, 1'b0 := 2};
v_err dist {1'b1 := 1, 1'b0 := 15};
}) `uvm_error("MYERR", "This is a randomize error");
a <= v_a;
if(v_err==0) b<=v_b; else b<=!v_b;
end
$finish;
end
Here is an example of deserialization for a UART
module top;
timeunit 1ns; timeprecision 100ps;
`include "uvm_macros.svh" import uvm_pkg::*;
// Upon a UART sync (the START) of new data the UART receives 1 byte of data + parity
// Nine cycles after the sync, the byte data received is transferred into the fifo
// Property uart interface
bit d_in; // from uart
bit start; // from comb logic
bit prty_ok; // from comb logic to check parity
bit clk; // bit clock
bit[7:0] fifo[0:7]; // fifo 8 deep
bit[7:0] rcv_data;
int index; // Support logic for index increment not included
initial forever #10 clk = !clk;
initial $timeformat(-9, 0, " ns", 10);
property p_uart; // UART receiver
bit[7:0] v_data, i=0;
bit v_parity;
@(posedge clk) start |->
##1 (1, v_data[i]=d_in, i+=1'b1)[*8]
##1 (1, v_parity=d_in, check_parity(v_data, v_parity));
endproperty
ap_uart: assert property(@ (posedge clk) p_uart );
property p_2fifo;
@ (posedge clk)
start ##9 prty_ok |-> ##1 fifo[index]==rcv_data;
endproperty
ap_2fifo: assert property(@ (posedge clk) p_2fifo );
ap_ifc2fifo: assert property(@ (posedge clk)
p_uart implies p_2fifo );
endmodule
Your use of tasks is interesting, particularly since I explained in a paper how SVA works using tasks. Understanding the SVA Engine, Verification Horizons - July 2020 | Verification Academy
You should easily be able to translate hose tasks into SVA. You can also use the action block and/or functions to update your testbench variables (see this link for examples of that)
SUPPORT LOGIC AND THE ALWAYS PROPERTY http://systemverilog.us/vf/support_logic_always.pdf