Two capabilities in SystemVerilog allow for the creation of a module that can produce a sine wave as an output: the ability to pass real values through port connections and DPI.
Obviously, to produce a sine wave, you need access to the sin function. This is where DPI is handy to add the math functions to your simulation. Here is an example of a package I created to contain the math functions:
task C Name = SV function name
"DPI" pure function real cos (input real rTheta);
"DPI" pure function real sin (input real rTheta);
"DPI" pure function real log (input real rVal);
"DPI" pure function real log10 (input real rVal);
endpackage : math_pkg
The import"DPI" construct defines a new function that you can use in your code that refers to a C function. In the case of the math functions listed above, they already exist in the libmath.so library built into Linux and so there is no additional code required.
Now that I have my math functions, I can create my module.
module sine_wave(output real
sampling_time = 5;
const real pi =
real time_us, time_s ;
real freq = 20;
real offset = 2.5;
real ampl = 2.5;
= #(sampling_time) ~sampling_clock;
assign sine_out =
offset + (ampl * sin(2*pi*freq*time_s));
Here I have used import in a different context. In this case import is used to make the code in my package available to the scope in which I import it. Now when I call the sinn function, it will use the DPI code from math_pkg to execute the function.
The sine_wave module also shows the use of passing a real value through a port. The output sine_out is of type real and is computed using the sin function.
SystemVerilog allows a real variable to be used as a port. The limitation is that a real variable can only be driven by a single driver. If that is a problem, you can make the module a Verilog AMS module and define the real variable as a wreal (real wire). By using wreal, you can have multiple drivers and use a variety of resolution types to solve any conflicts.