How to make a task call name using macro concatenation in SystemVerilog? - macros

In my SystemVerilog test, I'm trying to make a task call name by using macros.
If AAA_BLK is defined, I want the task call name replaced as test_aaa_proc();, and the same way for BBB_BLK and CCC_BLK.
`ifdef AAA_BLK
`define BLK_NAME aaa
`elsif BBB_BLK
`define BLK_NAME bbb
`elsif CCC_BLK
`define BLK_NAME ccc
`endif
task test_aaa_proc();
...
endtask
task test_bbb_proc();
...
endtask
task test_ccc_proc();
...
endtask
virtual task body();
test_``BLK_NAME``_proc ();
endtask
But, it fails with below errors.
Would you please advise?
test_``BLK_NAME``_proc ();
|
xmvlog: *E,EXPCPD
expecting a valid compiler directive [16(IEEE)].
test_``BLK_NAME``_proc ();
|
xmvlog: *E,MISEXX
expecting an '=' or '<=' sign in an assignment [9.2(IEEE)].
test_``BLK_NAME``_proc ();
|
xmvlog: *E,EXPCPD
expecting a valid compiler directive [16(IEEE)].
test_``BLK_NAME``_proc ();
|
xmvlog: *E,NOTDIR
`_proc: not a recognized directive or macro [2.7.3][16.3.1][16(IEEE)].

The `` syntax can only be used in the macro definition, not in the macro call. Refer to IEEE Std 1800-2017, section 22.5.1 `define.
You can create a new macro which will resolve into the task name that you want to call. Then, you can call that new macro from the body task. Here is a complete runnable example:
module tb;
`define AAA_BLK
`ifdef AAA_BLK
`define BLK_NAME aaa
`elsif BBB_BLK
`define BLK_NAME bbb
`elsif CCC_BLK
`define BLK_NAME ccc
`endif
`define TEST_TASK(block) test_``block``_proc
task test_aaa_proc();
$display("%m");
endtask
task test_bbb_proc();
$display("%m");
endtask
task test_ccc_proc();
$display("%m");
endtask
task body();
`TEST_TASK(`BLK_NAME);
endtask
initial body();
endmodule
This prints:
tb.test_aaa_proc

Related

EDA playground ERROR VCP5294 "Undefined package uvm_pkg"

I'm trying to compile a small UVM verification environment in EDA playground.
I'm getting this error:
EDA playground ERROR VCP5294 "Undefined package uvm_pkg.
The code attached below:
import uvm_pkg::*;
`include "reg_pkg.sv"
module testbench;
reg rst;
reg clk;
always #50 clk = ~clk;
initial begin
rst=0;
clk=0;
#100;
rst = 1;
`uvm_info("TESTBENCH",$sformatf("rst raised"),UVM_NONE);
end
reg_if reg_if_i();
assign reg_if_i.clk = clk;
assign reg_if_i.rst = rst;
WriteRegisters WriteRegisters_i(
.clk(reg_if_i.clk),
.rst(reg_if_i.rst),
.bus_en(reg_if_i.bus_en),
.bus_wr_rd(reg_if_i.bus_wr_rd),
.bus_data(reg_if_i.bus_data),
.bus_addr(reg_if_i.bus_addr)
);
initial begin
uvm_config_db#(virtual mux_if)::set(null,"*","reg_if_i",reg_if_i);
$dumpvars(0, testbench);
end
initial begin
run_test("reg_test1");
end
endmodule
Do you know why I get this error?
When using UVM on EDA Playground, you need to explicitly select a UMV library version in the left side panel. Currently "UVM/OVM" is set to None.
When I set it to UVM 1.2, the error goes away, as you can see below:
[2023-01-08 09:29:19 EST] vlib work && vlog '-timescale' '1ns/1ns' +incdir+$RIVIERA_HOME/vlib/uvm-1.2/src -l uvm_1_2 -err VCP2947 W9 -err VCP2974 W9 -err VCP3003 W9 -err VCP5417 W9 -err VCP6120 W9 -err VCP7862 W9 -err VCP2129 W9 design.sv testbench.sv && vsim -c -do "vsim +access+r; run -all; exit"
VSIMSA: Configuration file changed: `/home/runner/library.cfg'
ALIB: Library "work" attached.
work = /home/runner/work/work.lib
MESSAGE "Pass 1. Scanning modules hierarchy."
MESSAGE_SP VCP2124 "Package uvm_pkg found in library uvm_1_2."
Here is the modified EDA Playgound link.
It is also helpful to look at the examples in the left side panel: Examples -> UVM -> UVM Hello World

Cross-module reference resolution error from SV wait statement

I wanted to wait on the output variable of a task.
eg: wait(user_defined_task_name(output_variable_type_name) == 1)
In this example shown below, my intention is to make wait statement to be active from 0ns to 3ns (basically from the beginning of timestamp till t2=1)
Here is a working example;
class cl;
task run(output bit t);
$display("time=%0t , t=%0b",$realtime, t);
#1;
$display("time=%0t , t=%0b",$realtime, t);
#2;
t = 1;
$display("time=%0t , t=%0b",$realtime, t);
endtask
endclass
class c2 extends cl;
bit t2;
task run1();
wait(run(t2) == 1); // error from this line, what am i violating here?
$display("t2 working t2=%0b time = %0t", t2, $realtime);
endtask
endclass
module tmp;
c2 c2_h=new;
initial begin
c2_h.run1();
$display("test msg");
end
endmodule
eda output log:
Top Level Modules:
tmp TimeScale is 1 ns / 1 ns
Error-[XMREF] Cross-module reference resolution error testbench.sv, 19
Cross-module reference resolution error is found. Function is
expected, but actual target is not a function. Source info:
run(this.t2)
1 error CPU time: .116 seconds to compile Exit code expected: 0,
received: 1
A couple of problems with your code. A task does not return a value and cannot be used in an expression. You can only call it as a stand alone statement. But if you change run to a function functions cannot consume time.
In your particular example, you do not change the value of the t argument until the end of the task, and output arguments are copied out upon exiting the task, so you might as well just call the task run(t2) as a statement and it will block until returning.
task run1();
run(t2);
$display("t2 working t2=%0b time = %0t", t2, $realtime);
endtask
If on the otherhand run set the t argument somewhere in the middle of the task, and you want to continue the run1 task as soon as that happened, the you would have use a fork/join_none and a ref argument instead.
class cl;
task run(ref bit t);
$display("time=%0t , t=%0b",$realtime, t);
#1;
$display("time=%0t , t=%0b",$realtime, t);
#2;
t = 1;
#2;
$display("time=%0t , t=%0b",$realtime, t);
endtask
endclass
class c2 extends cl;
bit t2;
task run1();
fork
run(t2);
join_none
wait(t2 == 1);
$display("t2 working t2=%0b time = %0t", t2, $realtime);
endtask
endclass
When I run your code on the Cadence simulator, I get a different message:
xmvlog: *E,INVCTX The task 'run' cannot be used in this context.
Using the nchelp utility to get more information on that message:
A task or void function cannot be passed as an actual argument
because they do not return a value that can be used. They also cannot
be used as part of an expression.
In your simple example, there seems to be no need to use wait. You can simply call the task on its own:
task run1();
run(t2);
$display("t2 working t2=%0b time = %0t", t2, $realtime);
endtask

SystemVerilog compile error when declaring interface for a module (undeclared identifier [12.5(IEEE)])

I am learning how to use interfaces to wrap around a DUT (top-level module entity) in SystemVerilog. So, for this purpose, I came up with a basic example where the DUT is a simple synchronous RAM.
However, while I try to compile my code, I receive an error for every signal declared in the interface and used in the module ("undeclared identifier [12.5(IEEE)]"). I hope to get the precious help from this community to understand my error. I kept the code short and hopefully readable. Thank you in advance!
I tried removing the parameters and transform them into fixed numbers as well as using the define directive to make them global but did not help. The error, in fact, shows up also with signals that are not parametrized (such as oe signal).
// ********** Define the INTERFACE TO MODULE RAM: **********
interface clocked_bus
#(
// ---------- Parameters definition: ----------
parameter MEM_WIDTH=16, // word size of the memory
parameter ADDR_WIDTH=8 // => [2^ADDR_WIDTH locations]
)
(
// ---------- I/Os declaration: ----------
input clk
);
// ---------- Ports declaration: ----------
logic wr_rd_n_en, oe;
logic [MEM_WIDTH-1:0] data_out;
logic [2**ADDR_WIDTH-1:0] addr;
logic [MEM_WIDTH-1:0] data_in;
endinterface
// ********** Define the MODULE RAM: **********
module RAM(input clk, clocked_bus cb);
// ---------- CREATION OF MEM MATRIX: ----------
logic [MEM_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0];
// ---------- BEHAVIORAL ARCHITECTURE DEFINITION: ----------
always_ff#(posedge clk)
begin
if (wr_rd_n_en == 0)
if (oe ==1)
data_out <= mem[addr];
else
mem[addr] <= data_in;
end
endmodule
// ********** Define the MODULE RAM: **********
module top;
// Define the clock as 'free running process':
logic clk = 0;
always #10 clk = !clk;
// Instantiate the Interface:
clocked_bus #(.MEM_WIDTH(16), .ADDR_WIDTH(8)) cb(clk);
// Instantiate the DUT:
RAM mem1(clk, cb);
endmodule
I expect to compile however I get the following error:
interface worklib.clocked_bus:sv
errors: 0, warnings: 0
logic [MEM_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0];
|
xmvlog: *E,UNDIDN (lab.sv,31|43): 'ADDR_WIDTH': undeclared identifier [12.5(IEEE)].
logic [MEM_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0];
|
xmvlog: *E,UNDIDN (lab.sv,31|19): 'MEM_WIDTH': undeclared identifier [12.5(IEEE)].
if (wr_rd_n_en == 0)
|
xmvlog: *E,UNDIDN (lab.sv,36|21): 'wr_rd_n_en': undeclared identifier [12.5(IEEE)].
if (oe ==1)
|
xmvlog: *E,UNDIDN (lab.sv,37|17): 'oe': undeclared identifier [12.5(IEEE)].
data_out <= mem[addr];
|
xmvlog: *E,UNDIDN (lab.sv,38|23): 'data_out': undeclared identifier [12.5(IEEE)].
data_out <= mem[addr];
|
xmvlog: *E,UNDIDN (lab.sv,38|35): 'addr': undeclared identifier [12.5(IEEE)].
mem[addr] <= data_in;
|
xmvlog: *E,UNDIDN (lab.sv,40|19): 'addr': undeclared identifier [12.5(IEEE)].
mem[addr] <= data_in;
|
xmvlog: *E,UNDIDN (lab.sv,40|31): 'data_in': undeclared identifier [12.5(IEEE)].
module worklib.RAM:sv
errors: 8, warnings: 0
module worklib.top:sv
errors: 0, warnings: 0
When you access variables and parameters inside an interface, you should use the interface name to denote them. An interface provides a namespace capability by encapsulating those. Your code for RAM should look like the following:
module RAM(input clk, clocked_bus cb);
// ---------- CREATION OF MEM MATRIX: ----------
logic [cb.MEM_WIDTH-1:0] mem [2**cb.ADDR_WIDTH-1:0];
// ---------- BEHAVIORAL ARCHITECTURE DEFINITION: ----------
always_ff#(posedge clk)
begin
if (cb.wr_rd_n_en == 0)
if (cb.oe ==1)
cb.data_out <= mem[cb.addr];
else
mem[cb.addr] <= cb.data_in;
end
endmodule

can packed arrays be passed by reference to the task in systemverilog

Can s_clk be passed as argument to xyz task in below code?
module test(input logic m_clk, output [1:0] logic s_clk);
...
xyz (m_clk,s_clk);//assuming m_clks and s_clks are generated from top
...
task automatic xyz (ref logic clk1, ref [1:0] logic clk2);
...
endtask
endmodule
I have read your problem, first of all you have typo mistake
module test(input logic m_clk, output [1:0] logic s_clk);
task automatic xyz (ref logic clk1, ref [1:0] logic clk2);
instead of this you have to write
module test(input logic m_clk, output logic [1:0] s_clk);
task automatic xyz (ref logic clk1, ref logic [1:0] clk2);
For better understanding I have also share one demo code for packed arrays can be passed by reference to the task in systemverilog.
Here is code :
program main();
bit [31:0] a = 25;
initial
begin
#10 a = 7;
#10 a = 20;
#10 a = 3;
#10 $finish;
end
task pass_by_val(int i);
$monitor("===============================================%d",i);
forever
#a $display("pass_by_val: I is %0d",i);
endtask
task pass_by_ref(ref bit [31:0]i);
forever
begin
#a $display("pass_by_ref: I is %0d",i[0]);
$display("This is pass_by value a ====== %d \n a[0] ====== %0d ",a,a[0]);
end
endtask
initial
begin
pass_by_val(a);
end
initial
pass_by_ref(a);
endprogram
By running this example you can observe that packed arrays can be passed by reference to the task in systemverilog and its value is also reflected to it.
pass_by_val task will register the value of the variables
only once at the time when task is called. Subsequently when the variable changes its value, pass_by_val task cannot see the newer values. On the other hand, 'ref' variables in a task are registered whenever its value changes. As a result, when the variable 'a' value changes, the pass_by_ref task can register and display the value correctly.
I simulated Ashutosh Rawal's code and the output display is given below:
=============================================== 25
pass_by_val: I is 25
pass_by_ref: I is 1
This is pass_by value a ====== 7
a[0] ====== 1
pass_by_val: I is 25
pass_by_ref: I is 0
This is pass_by value a ====== 20
a[0] ====== 0
pass_by_val: I is 25
pass_by_ref: I is 1
This is pass_by value a ====== 3
a[0] ====== 1
$finish called from file "testbench.sv", line 13.
$finish at simulation time 40
V C S S i m u l a t i o n R e p o r t

How to use const in verilog

Instead of using
module ... ( .. ) ;
#15
endmodule
I want use
module ... ( ... ) ;
// GateDelay is a const, like in c language const int GateDelay = 15 ;
# GateDelay
endmodule
Or same thing
module ... ( ... ) ;
// assume Wordsize is defined at " define Wordsize 15 "
reg [ Wordsize -1 : 0 ] mem ;
endmodule
Can I do that wish in verilog ?
You've a few options :
Macros with `defines
parameters
localparams
Here's a small example with them all.
`define CONSTANT_MACRO 1 /* important: no ';' here */
module mymodule
#( parameter WIDTH = 5 )
(
input wire [WIDTH-1:0] in_a,
output wire [WIDTH-1:0] out_a
);
localparam CONSTANT_LOCAL = 2;
assign out_a = in_a + `CONSTANT_MACRO - CONSTANT_LOCAL;
endmodule
For the cases you listed, I would recommend parameters.
Like the C compiler directive, `define is global for the compilation. If your code is ever going to be used with code you don't control you will need to be careful here.
Parameters are always local to the module scope so identically named parameters in different design elements will not conflict with each other. They also have the advantage that they can be overridden on a per-instance basis.
module #(parameter DATA_WIDTH = 1) busSlave(
input [DATA_WIDTH-1:0] bus_data,
input bus_wr,
...
);
endmodule
module top;
//DATA_WIDTH is 32 in this instance
busSlave #(.DATA_WIDTH(32)) slave32(
.bus_data(data_0),
.bus_wr(wr_0),
...
);
//DATA_WIDTH is 64 in this instance
busSlave #(.DATA_WIDTH(64)) slave64(
.bus_data(data_1),
.bus_wr(wr_1),
...
);
endmodule