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:

SymbolMeaningPrecedence
-NOTHighest
*, /, %MUL, DIV, MODULO
+, -PLUS, MINUS
<<, >>,Logical Left/Logical Right
<<<, >>>Arithmetic Left/Right Shift
<, ⇐, >, >=Relative Comparsion
==, !=Equality Comparision
&, ~&AND, NAND
^, ~^XOR, XNOR
|, ~|OR, NOR
?:ConditionalLowest

NOTE

The precedence order is as expected - AND before OR. Follows conventional programming languages.

Constants


Verilog supports decimal, binary, octal, and hexadecimal constants:

NumberNo. of
Bits
BaseDecimal
Equivalent
Stored
3’b1013Binary5101
’b11unsizedBinary300000000..00011
8’b118Binary300000000..00011
8’b1010_10118Binary17110101011
3’d63Decimal6110
6’o426Octal34100010
8’hAB8Hexadecimal17110101011
42unsizedDecimal420000…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.