recomend the way to write a monitor in UVM with defferent event polarity - system-verilog

I am trying to implement a monitor for VDU(Video display unit) and the way the VDU can be programmed says that sync signals have controllable polarity. This means than according to VDU settings monitor should react on #posedge or #negedge event. Is there any way to pass the type (means posesge or negedge) via configuration data base or do something like this. Instead of write if(truth) #posedge else #negedge. And assertion also needs to be controlled this way but assertion at list designed to take event type as an argument but I am no sure config data base calls are allowed inside interface.

On option is to conditionally trigger an event. For example, you can have the bellow in you interface:
event mon_clk_ev;
bit mon_polarity;
always #(posedge clk) if ( mon_polarity) ->mon_clk_ev;
always #(negedge clk) if (!mon_polarity) ->mon_clk_ev;
Then you can use mon_clk_ev are the clock event in your monitor, interface, clocking block, or assertion.
mon_polarity could be assigned by your monitor, uvm_config_db, or other logic.
Example using uvm_config_db (Note using uvm_bitstream_t so it can be assigned with the uvm_set_config_int plusarg):
initial begin
start_of_simulation_ph.wait_for_state( UVM_PHASE_STARTED, UVM_GTE );
if (!uvm_config_db#(uvm_bitstream_t)::exists(null,"","mon_polarity")) begin
// default if not in database
uvm_config_db#(uvm_bitstream_t)::set(null,"*","mon_polarity",1'b1);
end
forever begin
void'(uvm_config_db#(uvm_bitstream_t)::get(null,"","mon_polarity",mon_polarity));
uvm_config_db#(uvm_bitstream_t)::wait_modified(null,"","mon_polarity");
end
end

You should write your code assuming positive polarity, but feed them through an xor operator.
logic signal; // your signal from DUT
logic signal_corrected; // signal with positive polarity
bit signal_polarity; // 0 = positive ; 1 = negative
assign signal_corrected = signal ^ signal_polarity;
Now you can use signal_corrected in your assertions. You can certainly call uvm_config_db#(bit)::get() from the interface if it has been set in your testbench. You might need to use uvm_config_db#(bit)::wait_modified() to wait for it to be set before you get it.

Related

Separating SystemVerilog nets before applying force

I want to force a signal down a hierarchy from my testbench. The modules are automatically created from schematics (changing design is not possible), and they are mostly based on wire type.
A code example can be found on EDA play ground.
//top level module
module dummy1(input A, output B);
dummy2 u_dummy2(A, B);
always #(A)
begin
assert (A == 1'b0) else $error("Force reached this level");
end
endmodule
module dummy2(input A, output B);
dummy3 u_dummy3(A, B);
endmodule
module dummy3(input A, output B);
assign B = A;
endmodule
If I force A in dummy3, it will change A in dummy2 and dummy1 which is something expected. I want to know if there is a way to separate A in dummy3 from A in dummy2 so that force is not applied to top level module.
module dummy_tb;
logic A, B;
dummy1 u_dummy1(A, B);
initial
begin
A = 0;
$display("step0: A=%b B=%b", u_dummy1.A,u_dummy1.B);
#1;
//force A1 to 1
force u_dummy1.u_dummy2.u_dummy3.A = 1'b1;
#1;
$display("step1: A=%b B=%b", u_dummy1.A,u_dummy1.B);
release u_dummy1.u_dummy2.u_dummy3.A;
#1;
$display("step2: A=%b B=%b", u_dummy1.A,u_dummy1.B);
//TODO: find something to separate A in u_dummy3 from A in u_dummy2, then force
end
endmodule
I can't think of a way to "separate" the nets without a change to the Verilog source code for the design modules, but you could achieve a similar effect by also forcing A in dummy2:
#1;
//force A1 to 1
force u_dummy1.u_dummy2.u_dummy3.A = 1'b1;
force u_dummy1.u_dummy2.A = 1'b0; // <-------- add this line
#1;
edaplayground
I think that this behavior results from a couple of quotes from the standard:
23.3.3 Port connection rules:
Each port connection shall be a continuous assignment of source to sink, where one connected item shall be
a signal source and the other shall be a signal sink. The assignment shall be a continuous assignment from
source to sink for input or output ports.
This makes dummy3.A the sink and dummy_tb.A the source.
10.6.2 The force and release procedural statements: A force procedural statement on a net shall override all drivers of the net—gate outputs, module outputs,
and continuous assignments—until a release procedural statement is executed on the net. When released,
the net shall immediately be assigned the value determined by the drivers of the net.
This makes dummy_tb.A a driver to the dummy3.A; So, basically verilog is forced to force all input ports on the way.
As a result, there is no way to do what you want without either forcing the port in the above level of hierarchy to a different value or to force outputs of continuous assignments in the low level module (force dummy3.B).

Possible workaround for async negedge reset?

I'd like to have a register with async reset signal, like following:
always #(posedge clk or negedge rst_n)
begin
if(!rst_n)
out <= 1'b0
else
out <= in
end
I have tried class AsyncReset() and withReset(). However, the generated code uses a posedge reset and the variable of AsyncReset() does not accept !.
Is there any workaround for this?
While you cannot invert the AsyncReset type directly (generally applying logic to an AsyncReset is bad because it can glitch), you can cast to a Bool and back:
val reset_n = (!reset.asBool).asAsyncReset
val reg = withReset(reset_n)(RegInit(0.U(8.W)))
Runnable example: https://scastie.scala-lang.org/ERy0qHt2Q3OvWIsp9qiiNg
I thought Jack's quick comment about avoiding glitches deserved a longer explanation.
Using an asynchronous reset creates a second timing arc in the design, from the reset to the end flop. The reset signal can be asserted at any time but needs to be de-asserted synchronous to the clock otherwise the flop can become metastable.
A common technique to do this is to use a reset synchronizer.
https://scastie.scala-lang.org/hutch31/EPozcu39QBOmaB5So6fyeA/13
The synchronizer shown in the above code is coded directly in Verilog as I do not know a way to keep the FIRRTL optimizer from pruning through constant optimization. The logic downstream of the reset sync can be either sync or async reset.

What is the best way to check an event occurred in the past in SVA?

I want to check in my design that when signal b get asserted, then signal a should have gotten asserted 3 to 5 cycles before.
I'm looking for the different ways to check that.
Currently I'm using the following logic
sequence s_test();
##1 $rose(a) ##[3:5] 1;
endsequence
property p_test();
##1 $rose(b) |-> s_test.triggered();
Is there a way to check that property without using the sequence triggered mechanism ? I guess I could also use something like $past(a, 3) || ... || $past(a, 5), but that's cumbersome.
Also what's the difference between the sequence triggered and matched mechanism ?
We can have two approaches here: cause then effect or effect because of cause.
Cause then effect approach:
You can use a forward-time-based assertion stating that when s_test is triggered, then b should go high in 1-5 clock period of time window:
s_test.triggered |-> ##[1:5] $rose(b);
Effect then cause approach:
Alternatively, if s_test is a signal, then you can use a glue logic which monitors past 5 values of s_test. Thereafter, the assertion checks that the earlier values of s_test must have atleast 1'b1 when b rises from 0 to 1.
bit[1:5] earlier;
always #(posedge clk) begin
earlier <= {s_test, earlier[1:5]}; // shift for 5 clocks
end
p1_past20: assert property(#(posedge clk)
$rose(b) |-> $countones(earlier) >= 1);
A similar discussion is available here and a reference is over here.
You can use $past something like below.
property test_past;
#(posedge clk)
$rose(b) |-> ##[3:5] $past(a);
endproperty
triggered & matched methods differ for single clock & multi clock sequences.
Both methods show end point of a sequence, but triggered method evaluates to true if the operand sequence has reached it's end point at that particular time and false otherwise.
Whereas matched method detects endpoint of sequence, referenced in multiclocked sequence. So it provides synchronization between 2 sequences and evaluates to true after match, untill arrival of 1st clock tick of destination sequence.
triggered status of a sequence is set in observed region and is persisted through the remainder of the timestep. Whereas matched status of a sequence is set in observed region and is persisted untill the observed region of the arrival of first clock tick of destination sequence after match.

How to use a parameter to add or remove a signal from a system verilog interface and modport

Here is a snippet of some interface code that has some parameterized sizes to it. The fourth parameter, HAS_BURST is something I have experimented with, but it has only resulted in compilation errors.
Effectively I am looking for a way to ADD/REMOVE a signal from a interface based on parameter. Is there a way to have a generic interface with removable signals?
interface axi_if
#(parameter ID_WIDTH = 4,
ADDR_WIDTH = 40,
DATA_WIDTH = 64,
HAS_BURST = 0)
();
logic aw_ready;
logic aw_valid;
logic [ID_WIDTH-1:0] aw_bits_id;
logic [ADDR_WIDTH-1:0] aw_bits_addr;
logic [7:0] aw_bits_len;
logic [2:0] aw_bits_size;
generate
if (HAS_BURST)
logic [1:0] aw_bits_burst;
endgenerate
logic [2:0] aw_bits_size;
modport slave (
output aw_ready,
input aw_valid,
input aw_bits_id,
input aw_bits_addr,
input aw_bits_len,
generate
if (HAS_BURST)
input aw_bits_burst,
endgenerate
input aw_bits_size
);
modport master (
input aw_ready,
output aw_valid,
output aw_bits_id,
output aw_bits_addr,
output aw_bits_len,
generate
if (HAS_BURST)
output aw_bits_burst,
endgenerate
output aw_bits_size
);
endinterface
`endif
No, there isn't. Ports aren't valid in generate blocks. Parameters can be used to asjust the width of a port but not remove it entirely. You could use an `ifdef to compile it conditionally but that's an all-or-none solution. There can't be some instances with the signal and others without it.
Having the signal unconditionally present is fine in many situations and it's the easiest way to handle this problem. Tie any unused inputs to logic 0 and unused outputs can remain unconnected.
If neither of these options work there's no other way than to define two different interfaces. Doing this by hand quickly becomes unmaintainable. If there are two variations now you can be sure a third one will be needed soon, then a fourth, a fifth... Many chip design companies have SystemVerilog code generators which create customized modules for each instance.

Convert unsigned int to Time in System-verilog

I have in large part of my System-Verilog code used parameters to define different waiting times such as:
int unsigned HALF_SPI_CLOCK = ((SYSTEM_CLK_PERIOD/2)*DIVISION_FACTOR); //DEFINES THE TIME
Now since I define a timescale in my files I can directly use these params to introduce waiting cycles:
`timescale 1ns/1ns
initial begin
#HALF_SPI_CLOCK;
end
Now I want to have time-specified delays everywhere. Means that the simulation will still respect all the timings even if I change the timescale. I would like to keep the parameters but wherever I have a wait statement, I need to specify the time. Something like
#(HALF_SPI_CLOCK) ns;
But this is not accepted by Modelsim. Is there a way to cast a parameter or an Unsigned int to a variable of type time in System-Verilog? Is there a way to specify the time unit? I have looked around but could not find any workaround.
The reason why I want to have control over the time and make it independent from the timescale is because I intend to change thetimescale later to try to make my simulation faster.
Other recommendations or thoughts are very welcome*
It is possible to pass time as a parameter in SystemVerilog, like:
module my_module #(time MY_TIME = 100ns);
initial begin
#MY_TIME;
$display("[%t] End waiting", $time);
end
endmodule
Or use multiplication to get the right time units, like:
module my_module2 #(longint MY_TIME = 100);
initial begin
# (MY_TIME * 1us);
$display("[%t] End waiting 2", $time);
end
endmodule
See runnable example on EDA Playground: http://www.edaplayground.com/x/m2
This will simulate and do what you want. While not the most elegant, it works.
task wait_ns(int num);
repeat (num) #1ns;
endtask
...
wait_ns(HALF_SPI_CLOCK);
This could have a negative impact simulation speed depending on how the timescale, clock events, and the unit of delay relate to each other.