Coding for Reuse Course - Module 1 Lesson 4
Parameters and Defines

In this lesson we will study the differences between parameters and defines, how to use and control both, and create a parameter file for our microprocessor.

1. Key differences between parameters and defines  

Parameters and defines create a flexible environment for your Verilog code; and enhance the readability of that code. They can be used to create scalable modules, allow different implementations of the same function for optimization, enable and disable features, work around compiler differences, and a host of other purposes. Before you use these constructs, you must understand how they work.

A `define is a compiler directive that creates a text substitution or a text macro that can accept arguments. All text between the definition name and the end of the line is used as part of the text substitution or macro. The define statement appears as follows :

`define <definition name> <definition text>

The name created by the define directive has a project scope unless it is subsequently removed via a `undef directive. The definition status of a particular name may be tested with the `ifdef and `ifndef directives.

A text substitution is invoked by the grave accent (`) followed by the definition name. A text macro is called by the grave accent (`) followed by the macro name and a comma separated list of arguments contained within parenthesis. i.e. :

<

`define MYTEXT the quick brown fox jumped over the lazy dogs back
`define EXCLUSIVE_OR(a,b) (a & ~b) | (~a & b)

$display `MYTEXT;
c = `EXCLUSIVE_OR(1,3);

Note that in some compilers and simulators, parameters may be used as arguments in text macros

A parameter, on the other hand, must be evaluated (as a generally 32-bit integer value) during the lexical pass, with its maximum width set by a compiler or simulator constraint. Some compilers or simulators are capable of evaluating a parameter as a real number. For general use however, assume evaluation will result in an integer

Parameters are particularly useful for improving the readability of code and creating scalable modules.

Parameters are defined as follows:

parameter <name> = <value>;

Other key differences

  1. Scope: A define persists for a project-level scope unless an "`undef"" directive is encountered; in which case it persists in all modules scanned prior to the "`undef" directive. I have not personally tried using an "`undef" directive on subsequent modules, there are advantages at a module level that uses multiple defines, but I cannot recommend this particular construct in reusable code simply for the sake of readability.

    On the other hand, parameters persist for an instance-level scope only. The instantiated module must explicitly declare the parameter either directly or via an "`include" directive. Subsequent instantiation of that module may then set that parameter's value for that particular instance using a "defparam" statement or named parameter passing. Any module that uses a parameter that is defined in an external file must explicitly declare that file via the use of an "`include" directive.

  2. Detection: A define may be detected by the compiler as existing or not existing. This makes it possible to conditionally compile your code to adhere to project constraints via the use of the "`ifdef" and "`ifndef" directives. This detection does not generate additional logic.

    Parameters require logic within your project to detect the state of that parameter and act upon it.

  3. Values: Parameters may be set on a per-instance basis with the use of a "defparam" statement or named parameter passing. This may be done within any instantiating module. Use of defparam statements is discouraged, since the defparam statements must be changed anytime an instance name changes, and therefore, can cause a lot of hard to find errors when they are missed. Named parameter passing is the preferred method. Named parameter passing is done as follows:

    <module name> #(.<Parameter name 1>(<value>),..., .<Parameter name n>(<value>))
    <instance name>(<instantiation>);

    To set a define to a different value requires the use of an "`undef" directive followed by a "`define" directive using the same variable name. Therefore, this type of construct is best contained within the top-level module only or within an external definition file.

  4. Definition: Many simulators and synthesizers will let you set define directives on the command line, allowing you to setup command scripts for specific projects.

    Parameters cannot be set on the command line; therefore, a PERL, C, Tcl, or other programming language may be required to copy current parameters to a master file so you can compile your project to meet a project-specific set of constraints.

2. Using a parameter file.  

Rule 6.6 declares that "Frequently reused parameters should be kept in separate files". Our instruction set is a prime candidate. Each module that references the instruction set then declares the instruction set file via the use of an "`include" directive to be able to use any of the instruction set parameters.

Instruction Set Preliminary Parameter File

3. Exercise  
  1. A 4-bit micro-controller with two registers (A and B) has the following instruction set:

    • 0h = No operation

    • 1h = Load A from data memory location specified in next 3 instruction memory nibbles (4-bit data).

    • 2h = Call subroutine. Store return address at data memory location 010h

    • 3h = Return. Next instruction will be fetched from address stored in data memory location 010h.

    • 4h = Jump. Fetch next instruction from address contained in the next 3 instruction memory nibbles (4-bit data).

    • 5h = Store A from in memory location specified in next 3 instruction memory nibbles (4-bit data).

    • 6h = Jump if zero. If the results of the last mathematical operation evaluates to zero, fetch next instruction from address contained in the next 3 instruction memory nibbles (4-bit data).

    • 7h = Exchange the contents of A and B.

    • 8h = Add contents of A to contents of B. Sum to B.

    • 9h = Subtract contents of B from contents of A. Difference to B.

    • Ah = Add contents of A and the carry from the previous mathematical operation to the contents of B. Sum to B.

    • Bh = Subtract the contents of B from the contents of A and the borrow from the previous mathematical operation. Difference to B.

    • Ch = Logically AND the contents of A with the contents of B and place the results in B.

    • Dh = Logically OR the contents of A with the contents of B and place the results in B.

    • Eh = Logically XOR the contents of A with the contents of B and place the results in B.

    • Fh = Halt all further instruction fetches and executions until the next reset.

    Create a parameter file for this micro-controller. Be sure to include a boilerplate.

  2. The 'B' version of this micro-controller replaces the no-operation instruction with one that will clear the carry flag. Using a definition, write a parameter file that supports both instruction sets. Include the differences and definition involved in your boilerplate.

  3. The 'C' version of this micro-controller replaces the exchange B with A instruction with one that merely moves the contents of B to A without altering the contents of B. Using definitions, write a parameter file that supports all three instruction sets. Include the differences and definitions involved in your boilerplate.