The 4-bit counter starts incrementing from 4'b0000 to 4'h1111 and then rolls over back to 4'b0000. It will keep counting as long as it is provided with a running clock and reset is held high.
The rollover happens when the most significant bit of the final addition gets discarded. When counter is at a maximum value of 4'b1111 and gets one more count request, the counter tries to reach 5'b10000 but since it can support only 4-bits, the MSB will be discarded resulting in 0.
0000 0001 0010 ... 1110 1111 rolls over 0000 0001 ...
The design contains two inputs one for the clock and another for an active-low reset. An active-low reset is one where the design is reset when the value of the reset pin is 0. There is a 4-bit output called out which essentially provides the counter values.
Electronic Counter Design
module counter ( input clk, // Declare input port for clock to allow counter to count up input rstn, // Declare input port for reset to allow the counter to be reset to 0 when required output reg[3:0] out); // Declare 4-bit output port to get the counter values // This always block will be triggered at the rising edge of clk (0->1) // Once inside this block, it checks if the reset is 0, if yes then change out to zero // If reset is 1, then design should be allowed to count up, so increment counter always @ (posedge clk) begin if (! rstn) out <= 0; else out <= out + 1; end endmodule
It's always best to get started using a very simple example, and none serves the purpose best other than "Hello World !".
// Single line comments start with double forward slash "//" // Verilog code is always written inside modules, and each module represents a digital block with some functionality module tb; // Initial block is another construct typically used to initialize signal nets and variables for simulation initial // Verilog supports displaying signal values to the screen so that designers can debug whats wrong with their circuit // For our purposes, we'll simply display "Hello World" $display ("Hello World !"); endmodule
module called tb with no input-output ports act as the top module for the simulation. The
initial block starts and executes the first statement at time 0 units.
$display is a Verilog system task used to display a formatted string to the console and cannot be synthesized into hardware. Its primarily used to help with testbench and design debug. In this case, the text message displayed onto the screen is "Hello World !".
ncsim> run Hello World ! ncsim: *W,RNQUIE: Simulation is complete.
A positive edge detector will send out a pulse whenever the signal it is monitoring changes from 0 to 1 (positive edge).
The idea behind a positive edge detector is to delay the original signal by one clock cycle, take its inverse and perform a logical AND with the original signal.
module pos_edge_det ( input sig, // Input signal for which positive edge has to be detected input clk, // Input signal for clock output pe); // Output signal that gives a pulse when a positive edge occurs reg sig_dly; // Internal signal to store the delayed version of signal // This always block ensures that sig_dly is exactly 1 clock behind sig always @ (posedge clk) begin sig_dly <= sig; end // Combinational logic where sig is AND with delayed, inverted version of sig // Assign statement assigns the evaluated expression in the RHS to the internal net pe assign pe = sig & ~sig_dly; endmodule
The module shown above is named pos_edge_det and has two inputs and one output. The design aims to detect the positive edge of input sig, and output pe. So we expect to see a pulse on pe whenever sig changes from value 0 to 1.
Data that cannot be processed is quite useless, there'll always be some form calculation required in digital circuits and computer systems. Let's look at some of the operators in Verilog that would enable synthesis tools realize appropriate hardware elements.
Verilog Arithmetic Operators
If the second operand of a division or modulus operator is zero, then the result will be X. If either operand of the power operator is real, then the result will also be real. The result will be 1 if the second operand of a power operator is 0 (a0).
|a + b||a plus b|
|a - b||a minus b|
|a * b||a multiplied by b|
|a / b||a divided by b|
|a % b||a modulo b|
|a ** b||a to the power of b|
An example of how arithmetic operators are used is given below.
module des; reg [7:0] data1; reg [7:0] data2; initial begin data1 = 45; data2 = 9; $display ("Add + = %d", data1 + data2); $display ("Sub - = %d", data1 - data2); $display ("Mul * = %d", data1 * data2); $display ("Div / = %d", data1 / data2); $display ("Mod %% = %d", data1 % data2); $display ("Pow ** = %d", data2 ** 2); end endmodule
ncsim> run Add + = 54 Sub - = 36 Mul * = 149 Div / = 5 Mod % = 0 Pow ** = 81 ncsim: *W,RNQUIE: Simulation is complete.
Verilog Relational Operators
An expression with the relational operator will result in a 1 if the expression is evaluated to be true, and 0 if it is false. If either of the operands is X or Z, then the result will be X. Relational operators have a lower precedence than arithmetic operators and all relational operators have the same precedence.
As we saw in a previous article, bigger and complex designs are built by integrating multiple modules in a hierarchical manner. Modules can be instantiated within other modules and ports of these instances can be connected with other signals inside the parent module.
These port connections can be done via an ordered list or by name.
Port Connection by ordered list
One method of making the connection between the port expressions listed in a module instantiation with the signals inside the parent module is by the ordered list.
mydesign is a
module instantiated with the name d0 in another module called tb_top. Ports are connected in a certain order which is determined by the position of that port in the port list of the module declaration. For example, b in the testbench is connected to y of the design simply because both are at the second position in the list of ports.
module mydesign ( input x, y, z, // x is at position 1, y at 2, x at 3 and output o); // o is at position 4 endmodule module tb_top; wire [1:0] a; wire b, c; mydesign d0 (a, b, a, c); // a is at position 1 so it is automatically connected to x // b is at position 2 so it is automatically connected to y // a is at position 3 so it is connected to z // c is at position 4, and hence connection is with o endmodule
Order of ports in the design module should be known for a correct connection.
This is very inconvenient because the order might change if a new port is added to the list or when the number of ports in the design is very large.