define vs parameter

there are two ways to define constants: the parameter, a constant that is local to a module and macro definitions, created using the `define compiler directive. A parameter, after it is declared, is referenced using the parameter name. A `define macro definition, after it is defined, is
referenced using the macro name with a preceding ` (back-tic) character. It is easy to distinguish between parameters and macros in a design because macros have a `identifier_name while a parameter is just the identifier_name without back-tic.

Parameters must be defined within module boundaries using the keyword parameter.
A parameter is a constant that is local to a module that can optionally be redefined on an instance-byinstance basis. For parameterized modules, one or more parameter declarations typically precede the port declarations in a Verilog-1995 style model, such as the simple register model in Example 1.

module register (q, d, clk, rst_n);
parameter SIZE=8;
output [SIZE-1:0] q;
input [SIZE-1:0] d;
input clk, rst_n;
reg [SIZE-1:0] q;
always @(posedge clk or negedge rst_n)
if (!rst_n) q <= 0; else q <= d;
endmodule

The Verilog-2001[5] version of the same model can
take advantage of both the ANSI-C style ports and module
header parameter list, as shown in Example 2.

module register2001
#(parameter SIZE=8)
(output reg [SIZE-1:0] q,
input [SIZE-1:0] d,
input clk, rst_n);
always @(posedge clk, negedge rst_n)
if (!rst_n) q <= 0; else q <= d;
endmodule

4. Parameters and Parameter Redefinition
When instantiating modules with parameters, in
Verilog-1995 there are two ways to change the parameters
for some or all of the instantiated modules; parameter
redefinition in the instantiation itself, or separate
defparam statements.
Verilog-2001 adds a third and superior method to
change the parameters on instantiated modules by using
named parameter passing in the instantiation itself (see
section 7).
5. Parameter redefinition using #
Parameter redefinition during instantiation of a module
uses the # character to indicate that the parameters of the
instantiated module are to be redefined.
In Example 3, two copies of the register from Example
1 are instantiated into the two_regs1 module. The SIZE
parameter for both instances is set to 16 by the #(16)
parameter redefinition values on the same lines as the
register instantiations themselves.

module two_regs1 (q, d, clk, rst_n);
output [15:0] q;
input [15:0] d;
input clk, rst_n;
wire [15:0] dx;
register #(16) r1 (.q(q), .d(dx),
.clk(clk), .rst_n(rst_n));
register #(16) r2(.q(dx), .d(d),
.clk(clk), .rst_n(rst_n));
endmodule

`define Inclusion
One popular technique to insure that a macro definition
exists before its usage is to use an `ifdef, or the new
Verilog-2001 `ifndef compiler directives to query for
the existence of a macro definition followed by either a
`define macro assignment or a `include of a file name
that contains the require macro definition.

`ifdef CYCLE
// do nothing (better to use `ifndef)
`else
`define CYCLE 100
`endif
`ifndef CYCLE
`include "definitions.vh"
`endif

The `undef compiler directive
Verilog has the `undef compiler directive to remove a
macro definition created with the `define compiler
directive.
Bergeron recommends avoiding the use of macro
definitions[11]. I agree with this recommendation.
Bergeron further recommends that all macro definitions
should be removed using `undef when no longer
needed[11]. I disagree with this recommendation. This
seems to be overkill to correct a problem that rarely exists.
Using the `define compiler directive to create global
macros where appropriate is very useful. Losing sleep
over the existence of global macro definitions and
tracking all of the `undef's in a design is not a good use
of time.
For the rare occasion where it might make sense to
redefine a macro, use `undef in the same file and at the
end of the file where the `define macro was defined.
Make sure that the last compiled macro definition is
likely to be the macro that you might want to access from
a testbench, because only one macro definition can exist
during runtime debug.
Again, using a `define-`undef pair should be
considered the last resort to a problem that could probably
be better handled using a better method.