/// Notes and Demos for LSU EE 4702-1 Spring 2001
// Miscellaneous
// Sources: Ci: Ciletti, Modeling, synthesis, and rapid prototyping
// with the Verilog HDL
// LRM: IEEE, Verilog Language Reference Manual
/// Contents
//
// Miscellaneous
// Include
// Defines define
// Removing Definitions (undef)
// Testing Definitions (ifdef,else,endif)
// Hierarchical Path Names
// Parameters
// Defparam
// Named Ports
// Procedural Continuous Assignments
// Other compiler directives. (Coming soon.)
/// Include
// LRM 16.5
// `include "PATHNAME"
//
// PATHNAME: A valid file or pathname.
//
// Insert contents of PATHNAME at current location.
`include "utility.v"
// Not a good use of include. Good uses further below.
module x();
handy h1(a,b,y);
endmodule
/// Defines
// LRM 16.3
// Below: define
/// Macro definition: `define NAME MACRO_TEXT
//
// NAME: An identifier
// MACRO_TEXT: Almost any text. Text ends at next line not ending with '\'
// Cannot start or end in the middle of a comment, operator, keyword,
// string, numbers, or identifier.
//
// Substitute occurrences of `NAME (note back tic) with MACRO_TEXT
// Replace occurrences of FOO with BAR.
`define FOO BAR
// One way of defining a constant.
`define BUS_WIDTH 16
// A five-line macro.
`define LOTS_OF_STUFF a = 1; \
b = 2; \
c = 3; \
$display("Thank you for using the LOTS_OF_STUFF macro."); \
$display("Have a nice day.");
`define EXP a + b
module mac_ex();
integer bus_w;
integer x, a, b, d;
initial begin
bus_w = `BUS_WIDTH;
x = `EXP + d;
end
endmodule
/// Macro Definition: `define NAME(FORMAL_ARGS) MACRO_TEXT
//
// NAME: An identifier
// FORMAL_ARGS: FORMAL_ARG1, FORMAL_ARG2, ...
// Each FORMAL_ARGn is an identifier.
//
// Macro Use
// Compute the minimum. Note parenthesis.
`define MIN(a,b) ((a)<(b)?(a):(b))
// Useful in for loops. (See example below.)
`define PP(a) a=a+1
/// WARNING: parenthesis around a omitted. Don't let it happen to you!
`define DOUBLE(a) 2*a
// Not satisfied with current keywords?
`define unless(cond) if(!(cond))
`define until(cond) while(!cond)
`define infinite_recur `infinite_recur
`define CHECK(var) \
if( ^var === 1'bx ) $display("Value undefined"); \
else if( var < 0 ) $display("Too low."); \
else if( var > 100 ) $display("Too high.");
module define_examples();
integer foo, bar, i, j;
initial begin
// The modelsim compiler will hang on the line below.
// `infinite_recur
// Why parenthesis should be put around macro arguments.
$display("Double of 2 is %d, double of 1+1 is %d",
`DOUBLE(2), `DOUBLE(1+1));
j = 0;
for(i=0; i<10; `PP(i))
begin
`unless( i < 9 ) $display("i is %d",i);
j = j + i;
end
bar = 2;
foo = `MIN(3,bar);
end
`ifdef DEBUG
always @( foo )
if( foo != bar ) begin
$display("It happened!");
$stop;
end
`endif
endmodule
/// Removing Definitions
// LRM 16.3
// `undef NAME
//
// NAME: An identifier.
//
// Remove definition of NAME, if any.
`define BREAKFAST eggs
// On second thought...
`undef BREAKFAST
`define BREAKFAST cereal
/// An example of poor style that will make debugging difficult.
`define TEMPMAC ((a)+(b)/(c))
// Lots of code, some using TEMPMAC
`undef TEMPMAC
`define TEMPMAC (2*(x)+(y))
/// A better use of `undef.
// Use with include to make custom alus.
`define WIDTH 64
`define ALUNAME alu_addsub
`define OP0(r,a,b) r=a+b;
`define OP1(r,a,b) r=a-b;
`include "generic_alu.v"
`undef ALUNAME
`undef OP0
`undef OP1
`define ALUNAME alu_andor
`define OP0(r,a,b) r=a&b;
`define OP1(r,a,b) r=a|b;
`include "generic_alu.v"
`undef WIDTH
`define WIDTH 32
`undef ALUNAME
`undef OP0
`undef OP1
`define ALUNAME alu_minmax
`define OP0(r,a,b) if( a < b ) r = a; else r = b;
`define OP1(r,a,b) if( a > b ) r = a; else r = b;
`include "generic_alu.v"
/// Another good use of `undef.
// The bean counter testbench description is being used to test 3 different
// modules.
`define BEANMOD beancount
`define BEANTESTMOD beantest
`include "beantest.v"
`undef BEANMOD
`define BEANMOD beancount_s
`undef BEANTESTMOD
`define BEANTESTMOD beantest_s
`include "beantest.v"
`undef BEANMOD
`define BEANMOD beancount_x
`undef BEANTESTMOD
`define BEANTESTMOD beantest_x
`include "beantest.v"
/// Testing Definitions
// LRM 16.4
// `ifdef NAME
// `else
// `endif
`define METHOD1
module mymod(somevar);
input somevar;
`ifdef METHOD1
// some stuff
initial begin
// METHOD1 code.
end
always @( somevar )
begin
end
`else
initial begin
// METHOD2 code
end
`endif
endmodule
/// Hierarchical Path Names
// LRM 12.4
// Hierarchical path name is full name of an identifier.
module top_mod();
lower_mod lm();
initial $display("avar is %d",lm.avar);
initial lm.avar = 3;
endmodule
module lower_mod();
reg avar;
initial avar = 1;
endmodule
module another_top_mod();
initial $display("avar is %d", top_mod.lm.avar);
endmodule
module hpn_one();
hpn_two h2a();
hpn_two h2b();
initial $display("States %d %d",
h2a.louisiana,
h2b.louisiana);
initial $display("Fruits: ",
h2a.h3a.apple,
h2a.h3b.apple,
h2b.h3a.apple,
h2b.h3b.apple);
initial $display("Consumer Electronics: ",
h2a.h3a.IBLOCK.tv,
h2a.h3b.IBLOCK.tv,
h2b.h3a.IBLOCK.tv,
h2b.h3b.IBLOCK.tv);
initial $display("Pets: ",
h2a.h3a.IBLOCK.ABLOCK.cat,
h2a.h3b.IBLOCK.ABLOCK.cat,
h2b.h3a.IBLOCK.ABLOCK.cat,
h2b.h3b.IBLOCK.ABLOCK.cat);
endmodule
module hpn_two();
reg louisiana, texas;
hpn_three h3a();
hpn_three h3b();
endmodule
module hpn_three();
reg apple;
wire banana;
initial begin:IBLOCK
reg tv;
reg radio;
begin:ABLOCK
reg cat;
reg dog;
cat = 111;
dog = 222;
$display("cat %d, dog %d",cat,dog);
end
begin:BBLOCK
$display("cat %d, dog %d",IBLOCK.ABLOCK.cat,IBLOCK.ABLOCK.dog);
end
end
endmodule
/// Parameters
// LRM 12.2
// Constants for use in a module.
// Module specifies default which can be overridden in instantiation.
/// Parameter Declaration
//
// module FOO(bar);
// parameter PARNAME1 = DEFAULT_PAR_VAL1;
// parameter PARNAME2 = DEFAULT_PAR_VAL2;
// ...
//
// PARNAME: An identifier.
// DEFAULT_PAR_VAL: An expression that evaluates to a constant at compile time.
//
// Specify default values for parameters.
// E.g., DEFAULT_PAR_VAL1 is the default for PARNAME1.
/// Specifying Parameter Values in Instantiations
//
// FOO #(PAR_VAL1,PAR_VAL2,..) MYFOO(MYBAR);
//
// Specify values used in an instantiation.
// E.g., PAR_VAL1 used for parameter 1 (overriding DEFAULT_PAR_VAL1).
/// Specifying Parameter Values in Modules
//
// defparam HIERARCHICAL_PATH_PARAMNAME = VAL;
//
// Set PARAMNAME in HIERARCHICAL_PATH to VAL
module param_examples();
// This is a constant, but be careful when using floating-point numbers.
parameter pi = 3.1415926535897932384626433832795028841971693993751058209;
// This is okay since compiler can compute expression.
parameter seconds_in_a_non_leap_year = 60 * 60 * 24 * 365;
// This is okay since compiler can compute expression because pi
// is a constant.
parameter twopi = 2 * pi;
integer i;
initial begin
// Correct use of a parameter.
i = seconds_in_a_non_leap_year / 12;
// Line below won't work, can't modify a parameter.
// pi = 3;
end
reg w,v;
initial begin w=1; v=2; end
// Won't work: w and v are not known at compile time. It doesn't
// matter that they are set at start of simulation and don't change.
// parameter wplusv = w + v;
endmodule
/// Using parameters as constants in an ALU module.
// Though sub works, the name is not needed throughout this file,
// so it should be declared within the module as a parameter.
`define sub 1
// Sum works. A parameter could not be used since a+b is not
// a constant expression.
`define sum a+b
module alu_p(result,op,a,b);
input op, a, b;
output result;
parameter add = 0;
// parameter sub = 1;
parameter pass_a = 2;
parameter pass_b = 3;
parameter and_op = 4;
parameter or_op = 5;
// Cannot use a parameter since a-b is not a compile-time constant.
// parameter diff = a - b;
reg [63:0] result;
wire [63:0] a, b;
wire [2:0] op;
always @( op or a or b )
case( op )
add : result = `sum;
`sub : result = a - b;
//`sub : result = diff;
pass_a : result = a;
pass_b : result = b;
and_op : result = a & b;
or_op : result = a | b;
default : result = 0;
endcase
endmodule
/// Using parameters for the width and delay for a multiplexor.
module mux_16_4(out,in0,in1,in2,in3,c);
input in0, in1, in2, in3, c;
output out;
parameter width = 16;
parameter del = 3;
reg [width-1:0] out;
wire [width-1:0] in0, in1, in2, in3;
wire [1:0] c;
always @( in0 or in1 or in2 or in3 or c )
# del case( c )
0: out = in0;
1: out = in1;
2: out = in2;
3: out = in3;
endcase
endmodule
module use_mux();
reg [1:0] c;
reg [7:0] in0_a, in1_a, in2_a, in3_a;
reg [15:0] in0_b, in1_b, in2_b, in3_b;
wire [7:0] out_a;
wire [15:0] out_b;
mux_16_4 #(8) mux_a(out_a,in0_a,in1_a,in2_a,in3_a,c);
mux_16_4 #(16,7) mux_b(out_b,in0_b,in1_b,in2_b,in3_b,c);
mux_16_4 mux_c(out_b,in0_b,in1_b,in2_b,in3_b,c);
and #(8) a1(x,a,b);
/// Note: The syntax for specifying module parameters and gate delays
// are similar, but the semantics (meaning) of a module
// parameter is very different than a gate delay.
endmodule
// Similar to use_mux, but use defparam to specify parameter values.
module use_mux2();
reg [1:0] c;
reg [7:0] in0_a, in1_a, in2_a, in3_a;
reg [15:0] in0_b, in1_b, in2_b, in3_b;
wire [7:0] out_a;
wire [15:0] out_b;
mux_16_4 mux_a(out_a,in0_a,in1_a,in2_a,in3_a,c);
mux_16_4 mux_b(out_b,in0_b,in1_b,in2_b,in3_b,c);
mux_16_4 mux_c(out_b,in0_b,in1_b,in2_b,in3_b,c);
and #(8) a1(x,a,b);
endmodule
module set_mux2();
defparam use_mux2.mux_a.width = 8;
defparam use_mux2.mux_b.width = 16;
endmodule
/// Named Ports
module norad_vending_machine(coffee,hot_chocolate,thermonuclear_war,tea);
input coffee,hot_chocolate,tea,thermonuclear_war;
// Code removed for security purposes.
endmodule
module np_example();
reg joe,hc,tea,war;
// Ooops.
norad_vending_machine mynvm(joe,hc,tea,war);
// No problem here: Simulator or other software that
// resolves instantiations will detect the port order problem,
// saving the world.
norad_vending_machine mynvm1(.coffee(joe),
.hot_chocolate(hc),
.tea(tea),
.thermonuclear_war(war));
endmodule
/// Procedural Continuous Assignments
// LRM 9.3
// assign REG_ASSIGNMENT
// deassign REG_NAME
//
// Used in procedural code.
//
// assign: Specify that continuous assignment is to start to a reg.
// deassign: End a continuous assignment.
// force REG_OR_NET_ASSIGNMENT
// release RET_OR_NET_NAME
//
// Used in procedural code.
//
// force: Specify that continuous assignment to start to a register or net type.
// release: End a continuous assignment.
// Characteristics
//
// While a continuous assignment is active ordinary assignment has no effect.
// A second continuous assignment replaces the old one.
/// These should only be used for special purposes, such as debugging.
module pca_example();
integer a, x;
wire [31:0] w, w1;
assign w1 = x + 1;
assign w = x + 1;
initial begin
a = 10;
x = 1;
// Set up a continuous assignment to a. Now a will be x + 1.
assign a = x + 1;
force w1 = x + 1;
$display("1 a is %d",a);
x = 2;
$display("2 a is %d",a);
#0;
$display("2 after 0 a is %d",a);
// The assignment below has no effect.
a = 20;
#0;
$display("20 a is %d",a);
deassign a;
$display("de a is %d",a);
a = 30;
$display("30 a is %d",a);
release w1;
end
endmodule
/// Other Compiler Directives
// Coming soon.