You are on page 1of 8

Verilog User Defined Primitives

A modeling technique whereby the user can virtually argument predefined gate
primitives by designing and specifying new primitive elements called user-defined
primitives (UDPs). These primitives are self-contained and do not instantiate other
primitives or modules.

Verilog provides a standard set of primitives, such as AND, NAND, NOT, OR, and NOR,
as a part of the language. These are also known as built-in primitives.

Instances of these new UDPs can be used in the same manner as the gate primitives to
represent the circuit being modeled. This technique can reduce the amount of memory
and improve simulation performance. The Verilog-XL algorithm accelerates the
evaluation of these UDPs.

However, designers occasionally like to use their custom-built primitives when


developing a design.Play Video

Each UDP has exactly one output, which can be in one of these states: 0, 1, or x. The tri-
state value z is not supported. Any input that has the value Z will be treated as X.

These two types of behavior can be represented in user-defined primitives:

1. Combinational UDP
2. Sequential UDP

A sequential UDP uses the value of its inputs and the current value of its output to
determine the next value of output.

Sequential UDPs provide an efficient and easy way to model sequential circuits such
as latches and flip-flops.

A sequential UDP can model both level-sensitive and edge-sensitive behavior. The
maximum number of inputs to a combinational UDP is 10. The maximum number of
inputs to a sequential UDP is limited to 9 because the internal state counts as an input.

Syntax
UDP begins with the reserved word primitive and ends with endprimitive.
Ports/terminals of primitive should follow. UDPs should be defined outside
the module and endmodule.

1. primitive UDP_name (output, input, ...);


2. port_declaration
3. [ reg output; ]
4. [ initial output = initial_value; ]
5. table
6. truth_table
7. endtable
8. endprimitive

UDP Rules

o UDP takes only scalar input terminals (1 bit).


o UDP can have only one scalar output. The output terminal must always appear
first in the terminal list.
o The state in a sequential UDP is initialized with an initial statement.
o State table entries can contain values of 0, 1 or X. Z values passed to a UDP are
treated as X values.
o UDPs are defined at the same level as modules.
o UDPs are instantiated exactly like gate primitives.
o UDPs do not support inout ports.

Verilog UDP Symbols


Verilog user-defined primitives can be written at the same level as module definitions,
but never between module and endmodule. They can have many input ports but always
one output port, and bi-directional ports are not valid. All port signals have to be scalar,
which means they have to be 1-bit wide.

Hardware behavior is described as a primitive state table that lists out a different
possible combination of inputs and their corresponding output within
the table and endtable. Values of input and output signals are indicated using the
following symbols.
Symbol Comments

0 Logic 0

1 Logic 1

x Unknown, can be either logic 0 or 1. It can be used as input/output or


current state of sequential UDPs

? Logic 0, 1 or x. It cannot be the output of any UDP

- No change, only allowed in the output of a UDP

ab Change in value from a to b where a or b is either 0, 1, or x

* Same as ??, indicates any change in the input value

r Same as 01 -> rising edge on input

f Same as 10 -> falling edge on input

p Potential positive edge on input; either 0->1, 0->x, or x->1

n Potential falling edge on input; either 1->0, x->0, 1->x

Combinational UDP
In combinational UDPs, the output state is determined solely as a function of the current
input states. Whenever an input changes state, the UDP is evaluated, and one of the
state table rows is matched. The output state is set to the value indicated by that row.
The maximum number of inputs to a Combinational UDP is 10.

Consider the following example, which defines a multiplexer with two data inputs, a
control input. But there can only be a single output.

1. // Output should always be the first signal in the port list


2. primitive mux (out, sel, a, b);
3. output out;
4. input sel, a, b;
5.
6. table
7. // sel a b out
8. 0 1 ? : 1;
9. 0 0 ? : 0;
10. 1 ? 0 : 0;
11. 1 ? 1 : 1;
12. x 0 0 : 0;
13. x 1 1 : 1;
14. endtable
15. endprimitive

A ? indicates that the signal can be either 0, 1 or x and does not matter in deciding the
final output.

Example

Below is a testbench module that instantiates the UDP and applies input stimuli to it.

1. module tb;
2. reg sel, a, b;
3. reg [2:0] dly;
4. wire out;
5. integer i;
6.
7. // Instantiate the UDP
8. // UDPs cannot be instantiated with port name connection
9. mux u_mux ( out, sel, a, b);
10. initial begin
11. a <= 0;
12. b <= 0;
13.
14. $monitor("[T=%0t] a=%0b b=%0b sel=%0b out=%0b", $time, a, b, sel, out);
15.
16. // Drive a, b, and sel after different random delays
17. for (i = 0; i < 10; i = i + 1) begin
18. dly = $random;
19. #(dly) a <= $random;
20. dly = $random;
21. #(dly) b <= $random;
22. dly = $random;
23. #(dly) sel <= $random;
24. end
25. end
26. endmodule

Sequential UDP
Sequential UDP allows the mixing of the level-sensitive and edge-sensitive constructs in
the same description. The output port should also be declared as reg type within the
UDP definition and can be optionally initialized within an initial statement.

Sequential UDP takes the value of its inputs and the current value of its output to
determine the next value of its output. The value of the output is also the internal state
of the UDP.

Sequential UDPs have an additional field in between the input and output field, which is
delimited by a ":" representing the current state.

Sequential UDP provides an easy and efficient way to model sequential circuits such as
latches and flip-flops. The maximum number of inputs to a Sequential UDP is limited to
9 because the internal state counts as an input. There are two kinds of sequential UDPs.

1. Level-Sensitive UDPs

Level-sensitive sequential behavior is represented the same way as combinational


behavior, except that the output is declared to be reg type, and there is an additional
field in each table entry.

This new field represents the current state of the UDP. The output field in a sequential
UDP represents the next state.

1. primitive d_latch (q, clk, d);


2. output q;
3. input clk, d;
4. reg q;
5.
6. table
7. // clk d q q+
8. 1 1 : ? : 1;
9. 1 0 : ? : 0;
10. 0 ? : ? : -;
11. endtable
12.
13. endprimitive

In the above code, a hyphen "-" on the last row of the table indicates no change in value
for q+.

1. module tb;
2. reg clk, d;
3. reg [1:0] dly;
4. wire q;
5. integer i;
6. d_latch u_latch (q, clk, d);
7. always #10 clk = ~clk;
8. initial begin
9. clk = 0;
10.
11. $monitor ("[T=%0t] clk=%0b d=%0b q=%0b", $time, clk, d, q);
12. #10; // To see the effect of X
13. for (i = 0; i < 50; i = i+1) begin
14. dly = $random;
15. #(dly) d <= $random;
16. end
17.
18. #20 $finish;
19. end
20. endmodule

2. Edge-Sensitive UDPs
In level-sensitive behavior, the inputs and the current state's values are sufficient to
determine the output value.

Edge sensitive behavior differs in that changes in the output are triggered by specific
transitions of the inputs.

A D flip-flop is modeled as a Verilog user-defined primitive in the example shown


below. Note that the rising edge of the clock is specified by 01 or 0?

1. primitive d_flop (q, clk, d);


2. output q;
3. input clk, d;
4. reg q;
5. table
6. // clk d q q+
7. // obtain output on rising edge of clk
8. (01) 0 : ? : 0;
9. (01) 1 : ? : 1;
10. (0?) 1 : 1 : 1;
11. (0?) 0 : 0 : 0;
12.
13. // ignore negative edge of clk
14. (?0) ? : ? : -;
15.
16. // ignore data changes on steady clk
17. ? (??): ? : -;
18. endtable
19. endprimitive

The UDP is instantiated and driven with random d input values in the testbench after a
random number of clocks.

1. module tb;
2. reg clk, d;
3. reg [1:0] dly;
4. wire q;
5. integer i;
6. d_flop u_flop (q, clk, d);
7. always #10 clk = ~clk;
8. initial begin
9. clk = 0;
10. $monitor ("[T=%0t] clk=%0b d=%0b q=%0b", $time, clk, d, q);
11. #10; // To see the effect of X
12. for (i = 0; i < 20; i = i+1) begin
13. dly = $random;
14. repeat(dly) @(posedge clk);
15. d <= $random;
16. end
17. #20 $finish;
18. end
19. endmodule

The output q follows the input d after 1 clock delay, which is the D flip-flop's desired
behavior.

You might also like