Hi I've following scenario and it's not working for me.
file: a.svh
a.svh defines some parameters and functions- let's say function xyz(b)
file b.sv
package b;
`include "a.svh"
typedef logic[(xyz(10)-1):0] h;
endpackage
Now the issue is, b.sv can't find xyz function in it's scope, even thought I'm tick-including a.svh in b.sv. Everything works fine if I don't use a package in b.sv file. (comment out package b and endpackage lines).
//package b;
`include "a.svh"
typedef logic[(xyz(10)-1):0] h;
//endpackage
Is it an illigal case in systemverilog?
I recreated your scenario on EDAplayground. I didn't get any errors.
A function is intended to be evaluated during simulation. Some simulators support evaluating function during compile/elaboration, but it doesn't appear to be a requirement.
SystemVerilog also has let, which is more appropriate for for compile time evaluation (it supports simulation time as well). Refer to IEEE Std 1800-2012 § 11.13 Let construct:
let declarations can be used for customization and can replace the text macros in many cases. The let construct is safer because it has a local scope, while the scope of compiler directives is global within the compilation unit. Including let declarations in packages (see Clause 26) is a natural way to implement a well-structured customization for the design code.
a.svh
function int xyz_func(int b);
return b;
endfunction
let xyz_let(b) = b;
design.sv (equivalent to your b.sv, EDAplayground requires design.sv to exist)
package b;
`include "a.svh"
typedef logic[(xyz_func(10)-1):0] hf;
typedef logic[xyz_let(10):1] hl;
endpackage
testbench.sv
module tb;
import b::*;
hf myhf;
hl myhl;
initial begin
myhf = -1;
myhl = -1;
$display("hf:%b left:%0d right:%0d", myhf, $left(myhf), $right(myhf));
$display("hl:%b left:%0d right:%0d", myhl, $left(myhl), $right(myhl));
end
endmodule
Output:
hf:1111111111 left:9 right:0
hl:1111111111 left:10 right:1
Related
So, I created my first system Verilog testbench by modifying the tutorial from https://verificationguide.com/systemverilog-examples/systemverilog-testbench-example-01/ ( In this tutorial a memory block is tested, I modified it for a simple AND gate).
There are seven files excluding the DUT file,
environment.sv
interface.sv
transactions.sv
generator.sv
testbench.sv ( topLevel testbench)
driver.sv
test.sv
I used Intel modelsim to compile these files.
While compiling, I got these errors in driver.sv and generator.sv
** Error: (vlog-13069) D:/Altera/Projects/AndGate/testbench/driver.sv(28): near ";": syntax error, unexpected ';', expecting '('.
** Error: (vlog-13069) D:/Altera/Projects/AndGate/testbench/generator.sv(4): near "trans": syntax error, unexpected IDENTIFIER, expecting ';' or ','.
Below are the corresponding files,
driver.sv
`define DRIV_IF mem_vif.DRIVER.driver_cb
class driver;
int num_trans;
virtual mem_intf mem_vif;
mailbox gen2driv;
function new(virtual mem_intf mem_vif, mailbox gen2driv);
this.mem_vif = mem_vif;
this.gen2driv = gen2driv;
endfunction
task reset();
wait(mem_vif.reset);
$display("--------- [DRIVER] Reset Started ---------");
`DRIV_IF.A <= 0;
`DRIV_IF.B <= 0;
`DRIV_IF.C <= 0;
wait(!mem_vif.reset);
$display("--------- [DRIVER] Reset Ended ---------");
endtask
task drive();
transaction trans;
gen2driv.get(trans);
$display("Num transactions : %0d", num_trans);
#(posedge mem_vif.DRIVER.clk);
`DRIV_IF.A <= trans.A;
`DRIV_IF.B <= trans.B;
trans.C = `DRIV_IF.C;
$display("\tA = %0h \tB = %0h \tC = %0h", trans.A, trans.B, `DRIV_IF.C);
num_trans++;
endtask
endclass
generator.sv
class generator;
var rand transaction trans;
mailbox gen2driv;
int repeat_count;
event ended;
function new(mailbox gen2driv, event ended);
this.gen2driv = gen2driv;
this.ended = ended;
endfunction
task main();
repeat(repeat_count) begin
trans = new();
if(!trans.randomize())$fatal("Random Generation failed");
gen2driv.put(trans);
end
-> ended;
endtask
endclass
Please, help me with this...
For future reference, it would really help to point to the line 28 and 4 in the respective files where the error is occurring as well as give the command line used to compile the code. But since I've seen this exact error before, I know it is because you put all of these files separately on your command line and not compiled together as a package.
Modelsim/Questa compiles every SystemVerilog file on the command line as a separate compilation unit. Identifiers declared in one compilation unit cannot be seen by other compilation units. When the generator and driver classes get compiled, it has no idea what transaction means and you get a syntax error. Modules and interfaces names exist in a separate namespace and the syntax where they are referenced allows them to used before their declarations have been compiled.
To remedy this, you could `include all you class files in testbench module, or the normal practice is putting them all in a package and importing the package. There is also a compilation mode where everything on the command line in one compilation unit, but that option is not scaleable as your designer get larger.
I also suggest reading these two posts I wrote:
https://blogs.sw.siemens.com/verificationhorizons/2010/07/13/package-import-versus-include/
https://blogs.sw.siemens.com/verificationhorizons/2009/05/07/programblocks/
I am trying to pass 2D real array to an SV function and return the same but I'm not able to execute this task successfully. Here is a simple reproducible code:
module Two_d_array_pass();
real x[2][2]='{'{1.0,2.0},'{3.0,4.0}};
real y[2][2]='{'{2.0,2.0},'{2.0,2.0}};
real z[2][2];
int i,j;
initial begin
foreach(x[i,j]) $display("x[%0d][%0d]=%0f",i,j,x[i][j]);
foreach(y[i,j]) $display("y[%0d][%0d]=%0f",i,j,y[i][j]);
z=mult(x,y);
end
function real mult(x,y);
real c[2][2];
int i,j;
foreach(c[i,j])
c[i][j]=x[i][j]*y[i][j];
return c;
endfunction
endmodule
and here is the error I get:
file: Two_d_array_pass.sv
c[i][j]=x[i][j]*y[i][j];
|
xmvlog: *E,DIMERR (Two_d_array_pass.sv,18|10): Bit-select or part-select dimensions do not match declaration.
c[i][j]=x[i][j]*y[i][j];
|
xmvlog: *E,DIMERR (Two_d_array_pass.sv,18|18): Bit-select or part-select dimensions do not match declaration.
Can anyone correct the code to achieve this task?
You need to change the arguments to be 2x2 dimensional as well.
function real mult(real x[2][2],y[2][2]);
But you also need to do it for the return type, but because of syntax limitations, unpacked array need a typedef for the return type.
typedef real real2x2[2][2];
function real2x2 mult(real x[2][2],y[2][2]);
Then you might as well use the typedef everywhere
module Two_d_array_pass();
typedef real real2x2[2][2];
real2x2 x='{'{1.0,2.0},'{3.0,4.0}};
real2x2 y='{'{2.0,2.0},'{2.0,2.0}};
real2x2 z;
initial begin
foreach(x[i,j]) $display("x[%0d][%0d]=%0f",i,j,x[i][j]);
foreach(y[i,j]) $display("y[%0d][%0d]=%0f",i,j,y[i][j]);
z=mult(x,y);
end
function real2x2 mult(real2x2 x,y);
foreach(x[i,j])
mult[i][j]=x[i][j]*y[i][j];
endfunction
endmodule
P.S. you do not declare the iterating variables i and j separately, they are implicit and local to the scope of the foreach statement. If you declare them separately, they become extra variables unused by the foreach loop.
module testy
#(
parameter W = 10,
parameter C = 2
)
(
aa
);
generate
if (W == 8)
begin:W8
if(C == 1)
begin:W8C1
typedef struct {
logic [8:0] so;
}my_struct;
end
if(C == 2)
begin:W8C2
typedef struct {
logic [10:0] so;
}my_struct;
end
end
endgenerate
input my_struct aa;
endmodule
I get this error:
irun(64): 14.20-p001: (c) Copyright 1995-2015 Cadence Design Systems, Inc.
file: testy.v
input my_struct aa;
|
ncvlog: *E,SVNOTY (testy.v,30|14): Syntactically this identifier appears to begin a datatype but it does not refer to a visible datatype in the current scope.
module worklib.testy:v
errors: 1, warnings: 0
ncvlog: *F,NOTOPL: no top-level unit found, must have recursive instances.
irun: *E,VLGERR: An error occurred during parsing. Review the log file for errors with the code *E and fix those identified problems to proceed. Exiting with code (status 2).
I thought generates were statically determined but I have problems compiling it - since parameters cant be overridden in packages and couldn't think of a way to do this in design which needs to be synthesized and didn't want to add interfaces or classes. Is there a bettwe way to do this. My struct has over 100 entries if I include all the combinations and use only what I want but I thought using generates I could trim it to what I want based on a set of parameters.
Thanks
Your problem is the scope of the typedef is local to the blocks inside your generate statements. If all you need to do is change the size of a data type, you can use a constant function call, with is statically determined. But then you run into another problem with your unpacked struct declaration - it is still local to the module and you will not be able to connect another struct to it with a matching data type. An interface would be a better solution and is synthesizable.
Another possibility is passing down a type parameter.
In a perfect world, I would be able to scope a localparam to the inside of a struct:
typedef struct {
logic [10:0] mantissa;
localparam exponent = -10;
} my_fixed_point_type;
But alas, this is not legal SystemVerilog. I've investigated using const ints (illegal), enums (not scoped to the struct, and requires "storage").
I might consider just embedding an int into the struct, and trust the synthesis tool to notice the values are only ever initialized, and strip them away, but some synthesis tools are just as likely to ignore initialization.
The only approach I've found so far that actually words is this abomination:
typedef struct {
logic [10:0] mantissa;
logic [25:0] _hidden;
} my_fixed_point_type;
`define FP_EXPONENT(var) $bits(var._hidden)
Since _hidden is never read from, I have high confidence that it will get stripped out at elaboration time, while the bit width of _hidden can be used to hide an (unsigned) integer constant. Ugly!
Surely there must be a better way to scope a constant to a struct in a way that is preserved in synthesis, but doesn't take up any actual bits. Or, do I have to take this up with the SystemVerilog 2016 committee?
There are a number of things you could do, but without knowing why you are trying to do this, it is difficult to recommend a good solution. Here are a few suggestions:
You can define an initial value to a typedef
typedef struct {
logic [10:0] mantissa;
int exponent = -10;
} my_fixed_point_type;
or use an anonymous enumerated type to prevent any other value ever being assigned to it
typedef struct {
logic [10:0] mantissa;
enum {value=-10} exponent = value;
} my_fixed_point_type;
or us a continuous assignment to the variable declared with this type
typedef struct {
logic [10:0] mantissa;
int exponent;
} my_fixed_point_type;
my_fixed_point_type fpv;
assign fpv.exponent = -10;
_hidden can be made signed with logic signed [25:0] _hidden;
It can be made a semi-constant with always_comb var._hidden = -10;
assign could also work but unlike always_comb simulators are not required to give errors with multiple drivers.
An alternative is to use use an interface instead of a struct, where you can use const or parameters (even functions).
I'm not sure how well a synthesizer will optimize either; you'll need to experiment. My guess is an interface with parameters will strip away the unused signals better then with a struct.
I just started to build a fixed point library as well and wanted to use a structure to hold the [full, integer and fractional] width of signals. I'm not even trying to do anything fancy, I just wanted to collect the parameters in a structure so it's easy to have access to them. Unfortunately no matter what I do the tools complain cause they think the structure content aren't constant - even if I only ever assign once.
For example:
typedef struct { int w, i, q; } fxpt;
fxpt dw = '{16, 1, 15};
wire signed [dw.w-1:0] din;
Or even if I would accept to have different structures for each signal so it's obvious everything is constant:
typedef struct { int w=18, i=1, q=17; } dw_constant;
dw_constant dw;
wire signed [dw.w-1:0] din;
I'm now reverting back to just having parameters directly in the code, such as:
parameter integer dw[0:2] = '{16, 1, 15};
wire signed [dw[0]-1:0] din;
Note that I haven't accessed the .i and .q parameter in the code snippet so it might look a bit useless, but when doing multiplication/addition those fields are important to have.
I was trying to synthesize a parameterized function where a structure is given as a parameter. I get the following error in the beginning of the parameterized function
"Syntax error at or near token 'virtual'."
I was trying to compile this simple package.
package def;
typedef struct packed {
logic[10:0] SIZE1;
logic[10:0] SIZE2;
} my_struct;
endpackage
import def::*;
virtual class my_class #(parameter my_struct new_struct = '{10,11});
static function [new_struct.SIZE2-1:0] adder (input [new_struct.SIZE1-1:0] a, b);
return a+b;
endfunction
endclass
module top
#(parameter my_struct new_struct2 = '{63,64})
(input logic [new_struct2.SIZE1-1:0] a, b,
output logic [new_struct2.SIZE2-1:0] y) ;
assign y = my_class #(.new_struct(new_struct2))::adder(a,b);
endmodule
Am I doing something wrong? Or this feature is not supported in Synopsys DC?
(Update: The code has been updated, this one can be synthesized with Synopsys DC)
According to http://www.sutherland-hdl.com/papers/2013-SNUG-SV_Synthesizable-SystemVerilog_paper.pdf § 5.6.7 Parametrized task/function arguments using static classes, the class must be virtual and defined in the $unit declaration space. This means the class cannot be defined inside a package. It is a weird requirements, as the paper points out.
Try moving the class out of the package. You could also try importing the function the the $unit scope, but not sure is this will work.
...
endpackage : def
import def::my_class; // or def::*;
...