Visualize
the Hardware: |
Describe
the Hardware: |
Comments: |
“Do
Nothing” circuit |
module
Gadget;
endmodule |
A
minimal Verilog description. The system has no I/O connections or internal
functionality.
Verilog is case-sensitive throughout. Keywords must
appear in lower case. |
“Do
Nothing” with I/O |
module
Gadget (a,b,c);
// Port modes input a,b; output
c;
endmodule |
I/O
port names
Valid Verilog names include alphanumerics, underscore
‘_’, and dollar sign ‘$. Verilog names can be quite long.
Describe
the “mode” (input or output) of each port.
Has no internal
functionality. |
Two-input
NAND gate based on assign
keyword |
module
Gadget (a,b,c);
/* Port modes */ input a,b; output c;
// Functionality assign c = ~(a &
b);
endmodule |
Alternative
comment style
Describe a NAND gate using two “bitwise”
operators.
NOTE: The “assign” technique is called a “continuous
assignment.”
|
|
Bitwise
Operators: ~
NOT &
AND |
OR ^
EXOR |
Bitwise
operators work on a bit-by-bit basis; for example:
“1 & 1” is
1 “01 | 10” is 11 (binary) |
Two-Input
NAND gate based on always
keyword |
module
Gadget (a,b,c);
// Port modes input a,b; output c;
// Registered identifiers reg
c;
// Functionality always @ (a or b) c <= ~(a
& b);
endmodule |
“Registered
identifiers” can generate a
logic value. The concept of a registered identifier is broader than simply
an array of flip-flops; combinational circuit outputs must also be
declared as registered identifiers when the “always” method (“procedural
assignment”) is used.
Describes a combinational circuit using
the procedural assignment technique. The “always” keyword means the
circuit always (continuously) watches the signals in the input list ( the
“@ (a or b)” part) and responds to changes in those signals by immediately
updating the output identifier.
Use the “<=” symbol to assign an
output inside an “always” block.
|
Two-input
NAND and EXOR |
module
Gadget (a,b,c,d);
// Port modes input a,b; output c; output d;
// Registered
identifiers reg c,d;
// Functionality always @ (a or b) begin c <= ~(a
& b);
d <= a ^ b; end
endmodule |
Can
have multiple “input” and “output” declarations
Can
enclose multiple output signal assignments inside a “begin” - “end” block;
everything between “begin” and “end” is treated as a single
statement.
|
Two-input
MUX |
module
Mux2 ( A, // A input B, // B input Sel, // Selector Y //
Output );
// Port modes input A,B,Sel; output Y;
// Registered
identifiers reg Y;
//
Functionality always @ (A or
B or Sel)
if (Sel==0)
Y <= A; else
Y <= B;
endmodule |
Demonstrates
ability to embed comments inside the code
Use “if-else”
technique to connect output “Y” to one of the two data inputs based on the
value of the data selector “Sel”.
The expression inside the
parentheses after “if” must evaluate to either “1” (true) or “0”
(false).
|
|
Relational
Operators: ==
Equal to !=
Not equal < Less
than >
Greater than <= Less than or
equal >=
Greater than or equal && AND ||
OR |
Relational
operators evaluate the comparison and return either true (1) or false
(0):
In the previous example, “Sel==0” evaluates to “1” if “Sel” is
zero, otherwise the comparison evaluates to
“0”. |
|
More
Operators: >>
Shift right << Shift left + Add -
Subtract *
Multiply / Divide %
Modulus |
NOTE:
Multiplication and division are not supported by standard hardware
synthesis tools
|
Two-input
MUX: Alternative method |
//
Functionality always @ (A or
B or Sel)
if (Sel)
Y <= B; else
Y <= A;
|
Since
“Sel” is a single-bit control signal, the expression inside the “(...)”
test can be written more concisely. |
Two-input
MUX: Another alternative method |
//
Functionality always @ (A or
B or Sel)
Y <= (Sel) ? B :
A; |
Here
the ternary (three-part) operator is used. The “if-else” test is embedded
into the assignment. Read the statement like this: “Is the control signal
‘Sel’ equal to 1? If yes, then use ‘B’ when making the assignment to ‘Y’,
otherwise use ‘A’ ”. |
Four-input
MUX |
module
Mux4 (
Data, // Data input Sel, // Selector Y //
Output );
// Port modes input [3:0] Data; input [1:0] Sel; output Y;
// Registered
identifiers reg Y;
//
Functionality always @ (Data
or Sel)
if (Sel == 0)
Y <= Data[0]; else if (Sel == 1)
Y <= Data[1]; else if (Sel == 2)
Y <= Data[2]; else Y <= Data[3];
endmodule |
Bus
widths are not included in the
port list.
A four-bit bus. The square brackets
define the bus width. The left-side number is the MSB.
A two-bit
bus is used for the data selector.
“if-else-if”
technique
Method for referring to individual bus
signals
|
Four-Input
MUX: Alternative method |
//
Functionality always @ (Data
or Sel)
case (Sel) 0: Y <= Data[0]; 1: Y <= Data[1]; 2: Y <= Data[2]; 3: Y <= Data[3]; default: Y <= Data[0]; endcase |
“case”
technique (similar to “switch” statement in C language). First match
between the case labels (left of colon) and the signal inside the
parentheses causes the associated assignment to be made.
“default”
keyword is a catch-all – if a match is not found, the default assignment
is made.
Use “begin-end” blocks to do multiple assignments for a
given case selector statement.
|
16-Input
MUX with custom behavior |
module
Mux16 (
Data, // Data input Sel, // Selector Y //
Output );
// Port modes input [15:0] Data; input [3:0] Sel; output Y;
// Registered
identifiers reg Y;
//
Functionality always @ (Data
or Sel)
casez
(Sel)
4’b0000: Y <=
Data[0];
4’b0001: Y <=
Data[1];
4’b01??: Y <=
Data[2];
default: Y <= Data[3]; endcase
endmodule |
Fully-specified
constant – the “4” numerical value says the constant is 4 bits wide, and
the ‘b says the digits are expressed in binary (use ‘d for decimal, ‘h for
hexadecimal, and ‘o for octal). Underscores can be used to improve
readability of long constants: 7’b010_0010
The question mark is a
“don’t care” when it appears inside a numerical constant. In this example,
the case selection ignores the two lowest bits and looks for a match on
the two highest bits. You need to use the ‘casez’ version of the ‘case’
statement when using “don’t cares”.
All other values of the “Sel”
control signal cause the fourth data bit to be selected.
Data bits
15 through 4 are effectively not used in this
example.
|
Code
Translator (specified as a truth table) |
module
Code_Translator ( Code_In,
Code_Out, );
// Port modes input [2:0] Code_In; output [2:0] Code_Out; // Registered identifiers reg [2:0] Code_Out;
//
Functionality always @
(Code_In) case (Code_In) 3’b000: Code_Out <=
3’b101; 3’b001: Code_Out
<= 3’b111; 3’b010:
Code_Out <= 3’b001;
3’b011: Code_Out <= 3’b000; 3’b100: Code_Out <=
3’b100; 3’b101: Code_Out
<= 3’b010; 3’b110:
Code_Out <= 3’b110;
3’b111: Code_Out <= 3’b011; endcase
endmodule |
The
“case” statement can be used to directly implement a truth-table
specification.
The “default” keyword is
optional – however, you can get unexpected results if the preceding cases
do not cover all possible input combinations.
|
Miscellaneous
Techniques |
{a,b}
{Data[13:12],a,b,Data[11:0]}
16{a}
assign
Y = (en) ? X : 1’bz; |
Group
signals together with curly braces
Complex grouping – in this
example, two signals are inserted between existing bus signals to form a
new bus.
Replicates the single-bit signal ‘a’ into a 16-bit bus
(each bus bit value is the same as ‘a’).
Tristate output control.
When the enable (‘en’) is active, the output gets the signal ‘X’,
otherwise the output is in high-impedance
state. |
4-bit
magnitude comparator |
module
Compare4 ( A, // Data input
A
B, // Data
input B
AltB, // A is less than
B
AeqB, // A is equal to
B
AgtB // A is > than
B );
// Port modes input [3:0] A,B; output AltB,AeqB,AgtB;
//
Registered identifiers reg
AltB,AeqB,AgtB;
// Functionality always @ (A or B) begin AltB <= (A < B); AeqB <=
(A == B);
AgtB <= (A > B); end
endmodule |
Since
the relational operator evaluates to either a “1” or a “0”, the result of
the comparison can be directly assigned to the single-bit
result.
|
Parameterized
design for n-bit comparator |
module
Compare4 ( A, // Data input
A
B, // Data
input B
AltB, // A is less than
B
AeqB, // A is equal to
B
AgtB // A is > than
B );
// Define bus width parameter BusWidth =
8;
// Port modes input [BusWidth-1:0]
A,B; output
AltB,AeqB,AgtB;
//
Registered identifiers reg
AltB,AeqB,AgtB;
// Functionality always @ (A or B) begin AltB <= (A < B); AeqB <=
(A == B);
AgtB <= (A > B); end
endmodule |
Define
bus width (use “8” in this example).
Make all subsequent
references to bus width using the parameter. This way entire design can be
adjusted simply by changing the original parameter
statement.
|
Parameterized
design (alternative method) |
`define
BusWidth
= 8; |
This
technique uses a the “define” compiler directive. All compiler directives
begin with the backwards apostrophe. The advantage of this method over the
“parameter” method is that CAD tools will allow you to specify the value
of your “define” directive outside your Verilog modules, obviating the
need to edit the Verilog files themselves. This is particularly valuable
if you want to deliver parameterizable designs to another designer without
that designer having to edit the
files. |