Verilog Introduction
Verilog Design Flow:
1. Developing a module:
Consider following ALU module as your Design Under Test (DUT):
2. Verilog Design for the above DUT:
module DUT(in1, in2, in3, out1);
input [1:0] in1, in2 ;
input [3:0] in3 ;
output [3:0] out1 ;
wire [3:0] mult_o ;
assign mult_o = in1 * in2 ;
assign out1 = mult_o + in3 ;
endmodule
3. Testbench to verify your DUT:
Now, you cannot simulate the actual inputs and inouts of your design, so you create a testbench (TB). Imagine testbench as a wrapper around your DUT which includes DUT and equipment required for testing (simulating and observing) your DUT.
In TB, define all inputs and inouts as reg and all outputs as wire.
At TB level, since you will be assigning all values to the inputs -> so reg
And since you will be observing all values of outputs -> so wire.
Note: All the blocks or constructs in a TB module need not be synthesizable, cause we won't be providing TB for synthesis tool. I will explain in following post, what is synthesizable and non-synthesizable constructs.
Tip: Do not observe values of outputs and reg variables at the time of their assignment in the DUT. Since $display task call can execute before or after the assignment of the variable. Therefore, always make sure to observe these value with some delay after their assignment in the DUT.
What are $monitor and $display?
-> These are system tasks.
What are system tasks?
-> These are system defined tasks recognizable to all the simulation tool's compiler in the market. These system task have a specific purpose and as the name suggests they follow a certain task.
$monitor:
Syntax: $monitor("Output data", list of vars) ;
1. This statement is written inside an initial block in TB.
2. Used to print data and Tb and DUT internal variables.
3. Whenever, it is encountered by the simulator, it becomes active and starts logging all the parameter arguments mentioned inside it.
4. It is executed every time, when at least 1 of the argument variable changes its value. $time can also be provided as one of the argument, though the change in the value of this argument is not considered for $monitor task's execution.
5. At a time, only one $monitor task can remain active .
6. When the simulator encounters, a new $monitor task, previously active $monitor task is deactivated, before activating the newly encountered $monitor task.
7. If the signal value changes at the same time when $monitor task remains activated, the simulator first allows all the signal values in the DUT and TB to be updated, and the updated value is logged by $monitor system task.
$display:
Syntax: $display("Output data", list of vars) ;
1. This statement is written inside an initial/always block in TB.
2. Every time simulator encounters a call to this task, it executes and deactivates the task.
3. Major difference is that like $monitor, this task doesn't remain activated till deactivation.
4. Another major difference is that, $monitor allows all the signal values to be updated and then executes, however, $display doesn't follow any such rules, and it's execution behavior is unpredictable. It can execute before, after or in between the values getting updated. Thus, must always be used with caution.
$time:
Syntax: $display($time, "Output data", list of vars) ;
Syntax: $monitor($time, "Output data", list of vars) ;
1. Used to display simulation time and not CPU system time.
2. If executed at the start of an initial block, it will print 0 units.
1. Developing a module:
Consider following ALU module as your Design Under Test (DUT):
Fig: ALU Desing |
2. Verilog Design for the above DUT:
module DUT(in1, in2, in3, out1);
input [1:0] in1, in2 ;
input [3:0] in3 ;
output [3:0] out1 ;
wire [3:0] mult_o ;
assign mult_o = in1 * in2 ;
assign out1 = mult_o + in3 ;
endmodule
3. Testbench to verify your DUT:
Now, you cannot simulate the actual inputs and inouts of your design, so you create a testbench (TB). Imagine testbench as a wrapper around your DUT which includes DUT and equipment required for testing (simulating and observing) your DUT.
In TB, define all inputs and inouts as reg and all outputs as wire.
At TB level, since you will be assigning all values to the inputs -> so reg
And since you will be observing all values of outputs -> so wire.
TB:
Fig: TB |
module TB ;
reg [1:0] in1_r, in2_r ;
reg [3:0] in3_r ;
wire [3:0] out1_w ;
reg [3:0] in3_r ;
wire [3:0] out1_w ;
alu my_alu(.in1(in1_r), .in2(in2_r), .in3(in3_r), .out1(out1_w)) ;
initial
begin
in1_r = 2'b10 ; in2_r = 2'b11 ; in3 = 4'b1001 ;
#1 ;
$display("IN1 = %d, IN2 = %d, IN3 = %d, OUT1 = %d", in1_r, in2_r, in3_r, out1_w ) ;
in1_r = 2'b00 ; in2_r = 2'b01 ; in3 = 4'b1101 ;
#1 ;
$display("IN1 = %d, IN2 = %d, IN3 = %d, OUT1 = %d", in1_r, in2_r, in3_r, out1_w ) ;
end
endmodule
Note: All the blocks or constructs in a TB module need not be synthesizable, cause we won't be providing TB for synthesis tool. I will explain in following post, what is synthesizable and non-synthesizable constructs.
Tip: Do not observe values of outputs and reg variables at the time of their assignment in the DUT. Since $display task call can execute before or after the assignment of the variable. Therefore, always make sure to observe these value with some delay after their assignment in the DUT.
What are $monitor and $display?
-> These are system tasks.
What are system tasks?
-> These are system defined tasks recognizable to all the simulation tool's compiler in the market. These system task have a specific purpose and as the name suggests they follow a certain task.
$monitor:
Syntax: $monitor("Output data", list of vars) ;
1. This statement is written inside an initial block in TB.
2. Used to print data and Tb and DUT internal variables.
3. Whenever, it is encountered by the simulator, it becomes active and starts logging all the parameter arguments mentioned inside it.
4. It is executed every time, when at least 1 of the argument variable changes its value. $time can also be provided as one of the argument, though the change in the value of this argument is not considered for $monitor task's execution.
5. At a time, only one $monitor task can remain active .
6. When the simulator encounters, a new $monitor task, previously active $monitor task is deactivated, before activating the newly encountered $monitor task.
7. If the signal value changes at the same time when $monitor task remains activated, the simulator first allows all the signal values in the DUT and TB to be updated, and the updated value is logged by $monitor system task.
$display:
Syntax: $display("Output data", list of vars) ;
1. This statement is written inside an initial/always block in TB.
2. Every time simulator encounters a call to this task, it executes and deactivates the task.
3. Major difference is that like $monitor, this task doesn't remain activated till deactivation.
4. Another major difference is that, $monitor allows all the signal values to be updated and then executes, however, $display doesn't follow any such rules, and it's execution behavior is unpredictable. It can execute before, after or in between the values getting updated. Thus, must always be used with caution.
$time:
Syntax: $display($time, "Output data", list of vars) ;
Syntax: $monitor($time, "Output data", list of vars) ;
1. Used to display simulation time and not CPU system time.
2. If executed at the start of an initial block, it will print 0 units.
« Previous Next »
Comments
Post a Comment