Internal Signals
Verilog modules use internal signals to connect between sub-modules and build the overall functionality. These signals can be nets or variables assigned using continuous assignments (assign
) or procedural assignments (always
blocks).
Precedence
Notice that we fully parenthesized the cout
computation, We could take advantage of operator precedence to use fewer parentheses:
assign cout = a&b | cin&(a|b);
The precedence from highest to lowest is:
Symbol | Meaning | Precedence |
---|---|---|
- | NOT | Highest |
*, /, % | MUL, DIV, MODULO | |
+, - | PLUS, MINUS | |
<<, >>, | Logical Left/Logical Right | |
<<<, >>> | Arithmetic Left/Right Shift | |
<, β, >, >= | Relative Comparsion | |
==, != | Equality Comparision | |
&, ~& | AND, NAND | |
^, ~^ | XOR, XNOR | |
|, ~| | OR, NOR | |
?: | Conditional | Lowest |
NOTE
The precedence order is as expected - AND before OR. Follows conventional programming languages.
Constants
Verilog supports decimal, binary, octal, and hexadecimal constants:
Number | No. of Bits | Base | Decimal Equivalent | Stored |
---|---|---|---|---|
3βb101 | 3 | Binary | 5 | 101 |
βb11 | unsized | Binary | 3 | 00000000..00011 |
8βb11 | 8 | Binary | 3 | 00000000..00011 |
8βb1010_1011 | 8 | Binary | 171 | 10101011 |
3βd6 | 3 | Decimal | 6 | 110 |
6βo42 | 6 | Octal | 34 | 100010 |
8βhAB | 8 | Hexadecimal | 171 | 10101011 |
42 | unsized | Decimal | 42 | 0000β¦00101010 |
NOTE
It is good practice to specify the length of the number in bits, even though the second row shows that this is not strictly necessary. If you donβt specify the length, one day you may be surprised when verilog assumes the constant has additional leading 0βs that you didnβt intend.
Underscores in numbers are ignored and can be helpful in breaking long numbers into more readable chunks.
If the based is omitted, the number is assumed to be decimal.
Hierarchy
Verilog modules can be organized into a hierarchy of sub-modules. Each sub-module can have its own inputs, outputs, and internal signals. The hierarchy can be visualized as a tree, where each module is a node in the tree.
To create a hierarchy of sub-modules, you can use the module
keyword to define a new module, and then instantiate it as a sub-module within another module.
The following example demonstrates the creation of a hierarchy of sub-modules:
module my_top_module;
// Instantiate a sub-module
my_sub_module sub_module1 (
.input1(in1),
.input2(in2),
.output1(out1),
.output2(out2)
);
// Instantiate another sub-module
my_sub_module sub_module2 (
.input1(out1),
.input2(in3),
.output1(out3),
.output2(out4)
);
// Define inputs and outputs of top-level module
input in1, in2, in3;
output out1, out2, out3, out4;
endmodule
module my_sub_module (
input wire input1,
input wire input2,
output wire output1,
output wire output2
);
// Define internal signals and logic of sub-module
reg internal1, internal2;
always @(posedge clk) begin
internal1 <= input1;
internal2 <= input2;
end
assign output1 = internal1;
assign output2 = internal2;
endmodule
In this example, my_top_module
has two sub-modules, sub_module1
and sub_module2
. Each sub-module has its own inputs and outputs, and can be instantiated multiple times within the top-level module.
Tristate
Verilog modules can have tristate outputs, which are outputs that can be in a high-impedance state (Z) in addition to the normal logic levels (0 and 1). Tristate outputs are useful for connecting multiple modules to a common bus.
To create a tristate output, you can use the tristate
keyword in the output port declaration.
The following example demonstrates the creation of a tristate output:
module my_module (
input wire clk,
input wire [7:0] din,
output tristate [7:0] dout,
output reg ready
);
// Define internal signals and logic of module
reg [7:0] internal_dout;
always @(posedge clk) begin
internal_dout <= din;
ready <= 1'b1;
end
assign dout = internal_dout;
endmodule
In this example, dout
is a tristate output that can be in a high-impedance state (Z) or a normal logic level (0 or 1).
Bit Swizzling
Verilog modules can have bit swizzling, which is the ability to rearrange the bits of a vector. Bit swizzling is useful for accessing individual bits of a vector in a different order than they are stored.
To create bit swizzling, you can use the []
operator to access individual bits of a vector.
The following example demonstrates the creation of bit swizzling:
module my_module (
input wire [7:0] din,
output [3:0] dout0,
output [3:0] dout1,
output [3:0] dout2,
output [3:0] dout3
);
// Define internal signals and logic of module
reg [7:0] internal_din;
assign dout0 = internal_din[3:0];
assign dout1 = internal_din[7:4];
assign dout2 = internal_din[6:4];
assign dout3 = internal_din[7:6];
always @(posedge clk) begin
internal_din <= din;
end
endmodule
In this example, din
is an 8-bit input vector, and dout0
, dout1
, dout2
, and dout3
are 4-bit output vectors. The bits of din
are rearranged using bit swizzling to produce the output vectors.
Delays in Verilog
In Verilog, delays can be specified for both inputs and outputs of modules. Delays can be defined using the @
symbol followed by a time value. There are two types of delays in Verilog: transport delays and inertial delays.
Transport Delays
Transport delays are associated with the input and output ports of a module. They represent the time it takes for a signal to propagate from the input to the output. Transport delays are specified using the @
symbol followed by a time value after the input or output port.
The following example demonstrates the use of transport delays on both input and output ports:
module my_module (
input wire clk,
input wire [7:0] din,
output reg [7:0] dout,
output reg ready
);
always @(posedge clk) begin
dout <= din;
ready <= 1'b1;
end
// Transport delay on input port
always @(posedge clk) begin
dout <= din @(posedge clk + 10ns);
ready <= 1'b1;
end
// Transport delay on output port
always @(posedge clk) begin
dout <= din;
ready @(posedge clk + 20ns);
end
endmodule
Inertial Delays
Inertial delays are associated with the internal signals of a module. They represent the time it takes for a signal to propagate through a logic gate. Inertial delays are specified using the @
symbol followed by a time value after the signal.
The following example demonstrates the use of inertial delays on internal signals:
module my_module (
input wire clk,
input wire [7:0] din,
output reg [7:0] dout,
output reg ready
);
always @(posedge clk) begin
dout <= din;
ready @(posedge clk + 10ns);
end
// Inertial delay on internal signal
always @(posedge clk) begin
dout <= din @(posedge clk + 10ns);
ready @(posedge clk + 20ns);
end
endmodule
It is important to note that transport delays are applied to the input and output ports of a module, while inertial delays are applied to the internal signals.