This is the sixth part of the Verilog Tutorial series. Click here for the first part.
Let us discuss about the above mentioned synthesizable constructs:
`define
Consider the code snippet as shown.
Here since `define B1 is mentioned on top, b gets the value of 1 wheres a and c remain unchanged (`elsif B1 condition will be satisfied).
For complex designs, we can have a large number of defines like this which can be imported from a separate defines file. (extension is .vh)
To import a file with defines, we add the file name on top of the module: `include filename.vh
Let us use `define to create a counter that modifies the parametrized counter used in the previous part into an up or down counter.
Verilog Code:
Note that the `define condition can be called from anywhere, but the condition exists throughout the design. For the above design, if I call `define UP, then an up counter will be realized. Otherwise by default, it will be a down counter.
Generate
Types:
1. Generate for-loop
2. Generate if-else
3. Generate case
Generate is used to allow multiple module instantiation (Generate for loop) or select the instance to be instantiated (Generate if-else and Generate case)
Let us look at our 3-bit up counter design.
Let us instantiate 3 modules of D Flip-Flop instead of performing flopping in the same module. This can be done in a compact form using the Generate for loop.
Notes:
1. Variable used in the instantiation process is called genvar.
2. Provide a name to the generate block as shown. (: followed by generate name)
3. The above module will generate 3 instances of D-Flip Flop just like how we require.
Similarly, one can write a code for Generate if-else and Generate case constructs.
As discussed before, every piece of Verilog code is written so as to model some hardware component. Our aim is to ensure that we stick to this rule. The code has to be completely synthesizable (to model hardware).
Synthesizable Verilog constructs that we have used till now in the tutorials:
module, input, output, reg, wire, assign, always, blocking & non-blocking assignments, if-else, case, parameter
Synthesizable Verilog constructs that will be discussed in this post:
`define, generate, for, verilog primitives
Non-synthesizable verilog constructs are used only in testbenches. They cannot be used to synthesize hardware. Examples are:
delays, fork-join
Let us discuss about the above mentioned synthesizable constructs:
`define
1. `define macro is a compiler directive that performs global macro substitution (it is similar in working to a parameter).
2. A parameter always resides within a module whereas `define can exist even outside of a module.
3. The define can be evaluated with `ifdef-`elsif-`else-`endif statements.
4. A `define remains active for all files until the macro is redefined or it is undefined using `undef compiler directive.
Consider the code snippet as shown.
`define B1 always @ * begin `ifdef A1 begin a = 1'b1; end `elsif B1 begin b = 1'b1; end `else begin c = 1'b1; end `endif end
Here since `define B1 is mentioned on top, b gets the value of 1 wheres a and c remain unchanged (`elsif B1 condition will be satisfied).
For complex designs, we can have a large number of defines like this which can be imported from a separate defines file. (extension is .vh)
To import a file with defines, we add the file name on top of the module: `include filename.vh
Let us use `define to create a counter that modifies the parametrized counter used in the previous part into an up or down counter.
Verilog Code:
module counter(cnt,clk,rst); parameter BITS = 3; input clk,rst; output [BITS-1:0]cnt; reg [BITS-1:0]cnt; wire [BITS-1:0]next_cnt; `ifdef UP assign next_cnt = cnt + 1'b1; //conditions `else assign next_cnt = cnt - 1'b1; `endif always @ (posedge clk or negedge rst) begin if(!rst) begin cnt <= {BITS{1'b0}}; end else begin cnt <= next_cnt; end end endmodule
Note that the `define condition can be called from anywhere, but the condition exists throughout the design. For the above design, if I call `define UP, then an up counter will be realized. Otherwise by default, it will be a down counter.
Generate
Types:
1. Generate for-loop
2. Generate if-else
3. Generate case
Generate is used to allow multiple module instantiation (Generate for loop) or select the instance to be instantiated (Generate if-else and Generate case)
Let us look at our 3-bit up counter design.
Let us instantiate 3 modules of D Flip-Flop instead of performing flopping in the same module. This can be done in a compact form using the Generate for loop.
module counter(cnt,clk,rst); input clk,rst; output [2:0]cnt; wire [2:0]next_cnt; wire [2:0]cnt; assign next_cnt = cnt + 1'b1; genvar i; //variable for generate for-loop generate for(i=0; i<3; i=i+1) begin :DFF_Instances //generate for-loop name is DFF_Instances DFlipFlop dff(.d(next_cnt[i]),.clk(clk),.rst(rst),.q(cnt[i])); end endgenerate endmodule
Notes:
1. Variable used in the instantiation process is called genvar.
2. Provide a name to the generate block as shown. (: followed by generate name)
3. The above module will generate 3 instances of D-Flip Flop just like how we require.
Similarly, one can write a code for Generate if-else and Generate case constructs.
For-Loop
For-loop is also a synthesizable construct, though it is less frequently used in digital design.
There are two cases where for loop can be distinctively useful:
1. Replicating a piece of code multiple times (as we saw in the above example where multiple instances where replicated using a for-loop under generate)
2. When using dynamic indexing to select a part (few bits) of a variable.
Verilog does not support dynamic indexing. It means that you cannot select a random number of bits from a variable dynamically.
For example:
Assume that I have a variable called temp which has to be stored in another variable declared as mem.
But I want to store only a few bits of temp in mem, where the bit position is indicated by a variable 'counter'. Example: If I want to store 8 bits of temp in mem, counter will indicate 8.
Then what one would normally do is:
module main; reg [31:0] mem; reg [31:0] counter; reg [5:0] temp; always @ * begin mem = temp[counter-1:0]; end endmodule
However, Verilog compilers will throw an error stating part select expressions must be constant. Since counter is a dynamic variable, the above code will not work.
Hence, the above program can be rewritten using for-loop as shown:
module main; reg [31:0] mem; reg [31:0] counter; reg [5:0] temp; always @ * begin integer i; for(i=0;i<counter;i++) mem[i] = temp[i]; end endmodule
Code Replication case
For-loop for creating multiple variables dynamically
Consider a case in which a master has to create variables addr, len and size for each slave based on the number of slaves (NUM_SLAVE).
This can be done using a dynamic for-loop with the following syntax:
`for(i=0; i<NUM_SLAVE; i=i+1) reg s`i::_addr; reg s`i::_len; reg s`i::_size; `endfor
Here `i:: will be replaced by the appropriate number from 0 to NUM_SLAVE.
Eg. If there is 1 slave, it will create variables s0_addr, s0_len and s0_size.
There is another construct that we use called the let construct.
`let construct is very similar to `define construct but the difference is that `let has a local scope whereas `define has a global scope.
So `let can be used when the expression is valid only for that particular module.
Verilog Primitives
Verilog language provides along with it a set of primitive constructs that can be used in design.
Examples:
Gates: and, nand, or, nor, xor, xnor, not
Buffer: buf
Tri-state buffer with active low enable: bufif0
Tri-state buffer with active high enable: bufif1
Buffer: buf
Tri-state buffer with active low enable: bufif0
Tri-state buffer with active high enable: bufif1
Transistor switch: pmos, nmos, cmos
Example Usage:
and (out, in1, in2) -> Here out gets the ANDed value of in1 and in2
bufif1 (inout_net, input_net, en) -> Here the inout_net will be driven by input_net whenever en is high
This is useful for modelling bidirectional pads.
No comments:
Post a Comment