The most important thing to remember about parameters is that they are
a VALUE that is referenced by a KEYWORD. The compiler has limited
means for evaluating the value of a parameter; and will frequently
generate additional logic, with subsequent delays when the current
value of a parameter is used as opposed to a compiler directive. The
major exceptions are parameters that control the logic size, such as
the depth or width of your function; parameters used to reference
state definitions in state machines; and parameters used to setup
fixed, reconfigurable structures, such as PLLs and DLLs.
Parameterized modules are generally used for generic, optimized,
common functions such as registers, counters, RAM, etc. Frequently
parameterized modules are replaced by vendor libraries.
These libraries, in turn, may use parameterized modules. In fact, up
until a few years ago, there was an industry recognized concept of
"library of parameterized macros" or LPMs for certain
functions (some very advanced).
Vendor library modules are not generally reusable. Therefore, you
should construct your own module that can be transported to any device
architecture. A properly designed parameterized module can be
synthesized by any software package.
2. Detailed Analysis of a Parameterized Module
Let us examine "dreg_r" from
Lesson 5 in some detail. The
first thing you will notice is that this is a conditional compile from
statement. Generic functions are used in many files such as test
benches or peripherals you may develop over time. Most compilers,
synthesizers, and simulators will croak if they see the same module
redefined. The "`ifndef" statement can prevent this; but
THERE ARE SOME CAVEATS.
In keeping with Rule 1.13, extreme
care must be used when naming your definition and module. Also,
if using a generic, un-altered version of a specific function, be
sure the definition and module names match in all included files.
If you test bench requires the same generic function as the
device-under-test, aka DUT (your module) it must take the
following steps to ensure that the version of that generic
function included in your project is used for simulation:
Do not include the module source within the main test file
unless a different module and definition name are used.
Instantiate the DUT before any other module that performs
functions other than interconnect.
If you do not use these precautions, it could cost hours of
debugging time (i.e. chasing ghosts) if the simulation failure
occurs in the version of a generic module within the DUT.
The definition name used for the conditional compile must be
defined before the end of the if statement. Hence the statement:
`define DREG 1
The module which we are examining features two parameters. The 'WIDTH'
parameter defines the bit width of the function. The 'RESET_VALUE'
parameter sets the state that the function will assume upon power-up
or asynchronous reset. These parameters MUST be explicitly declared
within a parameterized module before any 'defparam' statement or named
parameter passing has any effect.
Since parameters are an integer value, they may be used within
mathematical equations; such as the statement:
input [(WIDTH -1)]:0] d;
They may be also used within other parameters either as the value
(called aliasing) or as part of the value equation. Parameter values
are evaluated first, so they can also be used in "`define"
statements. A word of caution, however. The parameter value must be
resolved before it can be used within a "`define'. In other words,
a parameter used in one "`define" cannot rely on a
conditional compile from another "`define". Some synthesizers
do not support the use of a parameter in a "`define"
The "RESET_VALUE" sets the state the function assumes on
power-up or asynchronous reset events. However; it must be noted that
this state may be a "downstream" event. While some device
architectures support both an asynchronous preset and reset, many do
not. Instead, the compilers for these type of devices generally use
"De Morgan's theorem" to invert the output state of that
element at compile time and apply subsequent
"not gate pushbacks" for synchronous elements. Therefore,
in-depth simulations may not yield the expected results when observing
an element directly.
When you are performing a conditional compile on any self-contained
module, make sure that both the module declaration and the
"endmodule" statements are included between the
"`if" and "`endif" statements.
3. Basic Multiplexer
A multiplexer, called a 'mux' for short, is one of the simplest forms
of programmable logic. It is a pure sum of products, and is widely
used. Any logic can be constructed using only multiplexers. Most state
machines use muxes for state transitions. So why do I even choose to
Let us look at a standard mux. A standard mux selects one of two
signals ('A', 'B') to propagate to the output ('Q') based upon the
state of the select signal ('sel') as such:
The standard mux requires the fewest resources and incurs the least
routing 'costs' than any other construct when you are dealing with two
inputs that are controlled by a third input. Each bit requires only
one logic element within modern programmable devices. It is also easy
to understand and simulate. Almost every project I have dealt with
requires a standard mux. So let us add a parameterized version of our
standard mux to our microprocessor source code:
Skeleton with Parameterized Mux
If this mux is ideal, why do we need another one? The answer is
simple. When we exceed two inputs using conventional muxes, we must
implement a mux "tree". Example:
8 to 1 mux tree
We can see from this example is very expensive in terms of logic
element usage (11), logic levels (3), and routing 'costs'.
Before we proceed further, let me explain routing 'costs' for those of
you who have never routed a circuit. Multi-layer printed circuit
boards and the metal layers in a programmable device are very similar
in nature. Basically one layer is devoted primarily to horizontal
routes, and the other to vertical routes forming a matrix. At each
junction of a vertical and horizontal segment you may switch layers;
at a price. In PCBs this becomes a source of electromagnetic
interference (EMI). In programmable devices, this become a source for
routing delays, since the layer change generally requires an
electronic switch. In both cases, the layer switch also generates an
impedance mismatch, limiting maximum speed due to reflections and the
subsequent inter-symbol-interference (ISI). If most or all of a line
is used to avoid those problems, the that line as well as any layer
crossings to that line from the paired layer are also blocked.
Autorouters work by assigning a price to each scenario, and attempt
to minimize the total cost. Each possible problem is assigned some
cost or number of points. Since it is virtually impossible to test
every possible combination of placement and routing, a variety of
different algorithms are used. If this field of research interests
you, I suggest that you make a career of it; exploring it further via
education or other available resources.
4. Enhanced Multiplexer
Another way of avoiding the routing problems and logic delays can
be used with multiple enable muxes. Since we are using 4-input logic
elements, we can add a separate enable for each input as such:
This mux still fits within one logic element in modern programmable
devices, and requires more routing resources when you are dealing
with only two inputs. However, when we substitute our enhanced mux
into our 8 to 1 mux tree, we get this:
8 to 1 enhanced multiplexer
This example cuts our logic element usage to 6, and our logic levels
to two. The trade-off is that we must route two more select signals,
so smaller multiplexers lose this benefit. Since our microprocessor
uses several different registers and devices for source data; the
benefit exceeds the cost. We will add a parameterized version of our
enhanced mux to the source:
Skeleton with Parameterized Standard
and Enhanced Mutiplexers
There are a couple of extremely important things to note within
the added module. First and foremost, this module can also be modelled
with a 'always' block. However, when using an 'always' block
to model combinatorial logic, you MUST use a blocking assignment
(Rule 6.10). Otherwise you are more
susceptible to cascade effects within both simulators and compiles.
Second, make sure that the sensitivity list is complete
( Rule 6.11). Third, some combinatorial
logic will form a priority encoder; as it is within this case. Make
sure that when priority encoders are used, it is consistent with your
design intent. Last, the enhanced mux does not completely replace the
standard mux. It requires additional logic to generate the added select
signal, and incurs added routing costs for this signal.
To avoid the issues involved with using an 'always' block, I have,
instead, used a 'generate' block. a 'generate' block is essentially a '
for' loop that creates logic. In other words, each iteration of the
loop creates a new instance of the logic within the loop. The 'genvar'
controls the loop iterations, but can also be used as a variable
within the loop to select which product terms (pterms) are used in a
particular instance. Each instance name is created by appending the
value of the 'genvar' to the partial name succeeding the 'begin :'
part of the "for" statement.
When properly used, the enhanced mux can replace such items as
several 74<x>244 buffers driving a common bus, SSI multiplexers
with enables, etc.
What is a parameter?
Where do we use parameters in place of a 'define' statement?
Why don't we use the vendor library?
Why do we use a conditional compile for some parameterized
What it called when one parameter uses another parameter as its
What can possibly happen when we asynchronously reset a 4-bit
register to the value 4'b0101?
What is the short name for a multiplexer?
What consumes the fewest resources in logic and incurs the least
routing costs when we must select one of two signals based upon the
state of a third signal?
Explain routing costs.
I have two internal signals driving a bi-directional bus. The
input signal from this bus is used within the logic that
develops these signals. Which multiplexer should use?
Extra credit. Create a paramaterized module that creates multiple
instances of the following logic :
assign q = a ^ b;