Why use functions in verilog when there is module - verilog

Part 1:
I was always told to use functions in Verilog to avoid code duplication. But can't I do that with a module? If my understanding is correct, all functions can be re-written as modules in Verilog except that modules cannot be instantiated from the inside of an always block. Except, in this case, I can always stick with modules. Am I correct?
Part 2:
If I am correct, why can't the Verilog compiler be written in such a way that the modules get the treatment of a function? I mean, why can't the compiler allow the programmer to instantiate a module inside n block and stop supporting functions?

module != function. Their usage in verilog is completely different.
Functions are actually extended expressions and it is used in expressions. It can be used in rhs expression of the 'assign' statement or in expressions inside any procedural block.
Functions cannot consume time.
Functions must return a value.
Modules are used to express hardware hierarchy and contain concurrent procedural blocks (which might contain functions).
Modules may consume time.
Modules cannot return value. (output ports are not return values)
Potentially you can create a function which replaces internals of a single always block and write an equivalent module with an always block which returns function. But this is it.
You are not correct :). Verilog compiler cannot be written in such a way, because there is a verilog standard which every verilog compiler must follow. Otherwise it will not be verilog.

Related

Testing multiple configurations of parameterizable modules in a Verilog testbench

Say I have a Verilog module that's parameterizable like the below example:
// Crunches numbers using lots of parallel cores
module number_cruncher
#(parameter NUMBER_OF_PARALLEL_CORES = 4)
(input clock, ..., input [31:0] data, ... etc);
// Math happens here
endmodule
Using Verilog 1364-2005, I want to write a testbench that runs tests on this module with many different values NUMBER_OF_PARALLEL_CORES.
One option that I know will work is to use a generate block to create a bunch of different number_crunchers with different values for NUMBER_OF_PARALLEL_CORES. This isn't very flexible, though - the values need to be chosen at compile time.
Of course, I could also explicitly instantiate a lot of different modules, but that is time consuming and won't work for the sort of "fuzz" testing I want to do.
My questions:
Is there a way to do this by using a plusarg passed in from the command line using $value$plusargs? (I strongly suspect the answer is 'no' for Verilog 1364-2005).
Is there another way to "fuzz" module parameterizations in a testbench, or is using a generate block the only way?
Since $value$plusargs is evaluated at runtime, it can not be used to set parameter values, which must be done at compile-time.
However, if you use generate to instantiate multiple instances of the design with different parameter settings, you might be able to use $value$plusargs to selectively activate or enable one instance at a time. For example, in the testbench, you could use the runtime argument to only drive the inputs of a specific instance.

Allowing re-declaration of certain parameters inside package for simulation

I have a system that has some timeouts that are on the order of seconds, for the purpose of simulation i want to reduce these to micro- or milli-seconds.
I have these timeouts defined in terms of number of clock cycles of my FPGAs clock. So as an example
package time_pkg
parameter EXT_EN_SIG_TIMEOUT = 32'h12345678;
...
endpackage
I compare a counter against the constant global parameter EXT_EN_SIG_TIMEOUT to to determine if it is the right time to assert an enable signal.
I want have this parameter (as well as a bunch of others) defined in a package called time_pkg in a file called time_pkg.v and I want to use this package for synthesis.
But when I simulate my design in Riviera Pro (or Modelsim) i'd like to have a second parameter defined inside a file called time_pkg_sim.v that is imported after time_pkg.v and overwrites the parameters that share the same name as already defined in time_pkg.
If I simply make a time_pkg_sim.v with a package inside it with the same name (time_pkg) then Riviera complains since i'm trying to re-declare a package that's already been declared.
I don't particularly want to litter my hdl with statements to check if a simulation flag is set in order to decide whether to compare the counter against EXT_EN_SIG_TIMEOUT or EXT_EN_SIG_TIMEOUT_SIM
Is there a standard way to allow re-definition of paramters inside packages when using a simulation tool?
No, you can't override parameter in packages. What you can do is have two different filenames that declare the same package with different parameter values, and then choose which one to compile for simulation or synthesis.
It may be a better idea to have a massive ifdef with the simulator falg inside the package. That way your code would not be littered with ifdef everywhere, just concentrated in one place. Moreover, the code inside the modules itself would not need to change.

Metaprogramming in Verilog

I would like to generate some combinatorial logic, and I would like to use recursive functions for this (with predefined preprocessor arguments, of course).
Simple example: Factorial function
I have a reg [10:0] number; and I want to have the logic for counting it's factorial, but I want some predefined variable msb to be determine the MSB and have number[msb:0] as a starting number, and go on from there.
And module would receive the number and call fact_func(number) which would calcuate the factorial, but only the shortened one.
Is something like this possible in Verilog? Have functions generate logic?
I'm not totally sure what you're asking, but building logic with recursive function calls is very much possible in Verilog. You'll need to build a parameterized module that includes a generate block instantiating itself with a progressively smaller (or larger) parameter value, until you get to the base case.
Here's an example of it in action. You could easily modify this to generate the Fibonacci sequence.
Keep in mind, however, that generating blocks this way can synthesize very, very large. You will need to ensure the tools you're using are succeeding in optimizing it to a reasonable size.

Verilog primitives

Is there any difference between these two?
1.
and(O1,input1,input2);
2.
always(O1 or input1 or input2)
and(O1,input1,input2);
Does the primitive require an always block?
Or it will be accessed whenever values of output (O1) and inputs (input1,input2) changes?
Do the primitive requires an always block?
No! Just like 'assign' statements they do not need an always section.
In fact if you would have tried you would have gotten a syntax error as you can not instance a module or primitive in an always section.
Also you there would never be a need to put the output O1 in the sensitivity list.

Why are nonblocking assignments not allowed in Verilog functions?

I have read that use of nonblocking assignments is not allowed in Verilog functions. Can anyone suggest a plausible explanation for this?
The IEEE Std for Verilog (1364-2001), section "10.3.4 Function rules" states:
A function shall not have any nonblocking assignments.
The 1800-2009 IEEE Std elaborates more on this:
Functions shall execute with no delay. Thus, a process calling a
function shall return immediately. Statements that do not block shall
be allowed inside a function; specifically, nonblocking assignments,
event triggers, clocking drives, and fork-join_none constructs shall
be allowed inside a function.
The intention was for functions to be simple to evaluate in the Verilog event queue. If you need to advance time, use a task instead of a function.
Try not to think about functions in Verilog like functions in C:
Functions in Verilog are designed to be a developer-friendly way to instantiate identical combinational logic in multiple places at once rather than having to write it over again / make a module for it. A lot of "newbies" to Verilog try to rationalize functions like they are C functions, and while they are "returning" a value, it is easier (and more correct) in the end to conceptualize them as blocks of combinational gates.
Note that this is different from a "task", which are more generally used for executing things "in order", which would probably be more useful in a testbench situation than a function
As you learn Verilog try not to rationalize the HDL you write as "code", because it is a different style of thinking.
EDIT: Took out some bad explanation on my part

Resources