View Course Path

# Verilog code for priority encoder – All modeling styles

• Describe the Priority Encoder using different levels of abstraction in Verilog – Gate levelDataflow, behavioral, and structural modeling.
• Generate the RTL schematic for the Priority Encoder.
• Write the testbench.
• Generate simulated waveforms.

Contents

## What is a Priority Encoder?

Before explaining the priority encoder, you must know what an encoder is.

An encoder is a combinational circuit. It has 2^n input lines and n output lines. It takes up these 2^n input data and encodes them into n-bit data. In other words, it produces the binary code equivalent of the input line, which is active high.

But, a normal encoder has a problem. If there is more than one input line with logic 1 value, it will encode the wrong output. It only works when only one of the inputs is high. It malfunctions in the case of multiple high inputs.

Thus, to solve the above disadvantage, we “prioritize” the level of each input. Hence, if multiple input lines are selected, the output code will correspond to the input with the highest designated priority. This type of encoder is called the Priority Encoder.

Now, we will learn how to design a 4:2 Priority Encoder using different modeling styles in Verilog.

## Gate Level Modeling

This is virtually the lowest abstraction layer, which is used by designers for implementing the lowest level modules, as the switch level modeling isn’t that common. As the name suggests, gate-level modeling makes use of the gate primitives available in Verilog. The prerequisite for this style is knowing the basic logic diagram of the digital circuit that you wish to code. You can learn everything about the Gate level modeling method in Verilog over here.

As we are describing a Priority Encoder using Gate-Level modeling, let’s see the logic circuit:

From the circuit, we can observe that one AND, two OR and one NOT gates are required for designing. Let’s start coding.

### Gate level Modeling for 4:2 priority encoder:

As any Verilog code, we start by declaring the `module` and terminal ports.

```module priority_encoder_42(A0,A1,Y0,Y1,Y2,Y3);
....
endmodule```

Note that we declare outputs first followed by inputs as the built-in gates also follow the same pattern.

Let’s declare the input and output ports.

```input Y3, Y2, Y1, Y0;
output A0, A1;

```

Now, we can declare the intermediate signals. These are signals that are not the terminal ports. From the above circuit, the signals from NOT and AND gates can be treated as intermediate signals.

```wire y2bar; //not of y2
wire and_out; // and of y2bar and y1
```

Time for us to define the logic gates. We use the gate (<outputs>,<inputs>) syntax to use the in-built gates in Verilog.

```not(y2bar, y2);
and(and_out, y2bar, y1);
or(A1, Y3, Y2);
or(A0, and_out, Y3);

```

So, our final code is:

```module priority_encoder_42(A0,A1,Y0,Y1,Y2,Y3);

input Y3, Y2, Y1, Y0;
output A0, A1;

wire y2bar; //not of y2
wire and_out; // and of y2bar and y1

not(y2bar, y2);
and(and_out, y2bar, y1);
or(A1, Y3, Y2);
or(A0, and_out, Y3);

endmodule

```

## Dataflow Modeling

In this modeling technique, we use logic equations to describe the flow of data from input to the output. We need not bother about the gates that make up the circuit. Hence, it is much easier to construct complex circuits using this level of abstraction since there is no need to know the actual physical layout. You can read all about the dataflow modeling technique in Verilog over here.

To describe the circuit using the logic equation, this modeling uses the keyword `assign`. We can see how it is done.

Shouldn’t we know the logic equation for the priority encoder?

Correct! Here it is:

A1 = Y3 + Y2

A0 = Y3 + Y1Y2′

Now, let’s proceed with the coding.

### Dataflow modeling of 4:2 Priority Encoder

As always, we start with the `module` and port declarations:

```module priority_encoder_datafloe(A0,A1,Y0,Y1,Y2,Y3);
input Y0,Y1,Y2,Y3;
output A0,A1;```

Now, we have to describe the flow of data to the outputs using `assign`.

```assign A1 = Y3 + Y2;
assign A0 = Y3 + ((~Y2)&Y1);```

Hence, our final code:

```module priority_encoder_datafloe(A0,A1,Y0,Y1,Y2,Y3);
input Y0,Y1,Y2,Y3;
output A0,A1;

assign A1 = Y3 + Y2;
assign A0 = Y3 + ((~Y2)&Y1);

endmodule```

## Behavioral Modeling

Behavioral Modeling is the highest level of abstraction in Verilog HDL. We can describe the circuit by just knowing how it works. Moreover, there’s additional good news! We do not need to know the logic circuit or logic equation. We just need a simple truth table. You can check out our in-depth guide on behavioral modeling in Verilog here.

 Y3 Y2 Y1 Y0 A1 A0 0 0 0 1 0 0 0 0 1 x 0 1 0 1 x x 1 0 1 x x x 1 1

With this truth table, we can design our priority Encoder using Verilog.

Let’s see how:

## Behavioral Modeling of 4:2 Priority Encoder

As usual, starting with the `module` and the port declaration.

```module priority_encoderbehave(A, Y);

input [3:0]Y;
output reg [1:0]A;```
We have to mention output as `reg` in behavioral modeling. As we use procedural assignments in this style of modeling, we have to make sure the outputs retain their value until the next value is given to them.
Moving on,
```[email protected](Y)
begin
....
end```

What we have declared in brackets is the sensitivity list. Here, depending on the value of `Y`, the statements between `begin` and `end` will be executed. The `always` keyword will make sure that the statements get executed every time the sensitivity list is triggered.

In between `begin` and `end`, we write the procedure for how the system works:

```casex(Y)

4'b0001:A = 2'b00;
4'b001x:A = 2'b01;
4'b01xx:A = 2'b10;
4'b1xxx:A = 2'b11;
default:\$display("Error!");

endcase```

The `case` compares an expression to a series of cases and executes the statement or statement group associated with the first matching case. We have used `casex`, which is a special version of the `case`. This will treat the x and z values as don’t cares.

Therefore, our final code will be:

```module priority_encoderbehave(A, Y);

input [3:0]Y;
output reg [1:0]A;

[email protected](Y)
begin

casex(Y)

4'b0001:A = 2'b00;
4'b001x:A = 2'b01;
4'b01xx:A = 2'b10;
4'b1xxx:A = 2'b11;
default:\$display("Error!");
endcase
end
endmodule```

## Structural Modeling

Structural modeling describes the hardware structure of a digital system. It is somewhat similar to gate-level modeling. The only difference is it doesn’t include any built-in gates. We create separate modules for each gate and then integrate to form the whole circuit

### Logic Circuit

In the case of 4:2 priority encoder, we require two OR, an AND and a NOT gates.

We have to structurize each gate with their respective `module`.

## Structural Modeling of 4:2 Priority Encoder

We declare the `module` as or_gate. Then, we declare input and output ports

```module or_gate(c,a,b);
input a,b
output c;```

Then, we use `assign` statement to write the logical expression for OR.

`assign c = a|b;`

Thus our OR gate module will be:

```module or_gate(c,a,b);
input a,b;
output c;

assign c = a|b;

endmodule```

Similarly, we do for AND gate:

```module and_gate(z,x,y);

input x,y;
output z;

assign z = x&y;

endmodule

```

And NOT gate:

```module not_gate(f,e);

input e;
output f;

assign f = ~e;

endmodule```

Note: We keep variables for assigning inputs and outputs in one module different from others. This ensures mixing up of signals does not happen during a simulation.

Now we can proceed describing the Priority Encoder as the top-level module.

```module priority_encoder_struct(A0,A1,Y0,Y1,Y2,Y3);

input Y0, Y1, Y2, Y3;
output A0,A1;```

Time for us to combine these individual modules for logic gates into one single module for the top module. This is done with the help of a concept called module instantiation in which top modules are build using lower modules.

Using the logic circuit, we will instantiate the lower modules in this top using instantiation by port name.

```not_gate u1(.f(y2bar), .e(y2));
and_gate u2(.z(w1), .x(y2bar), .y(y1));
or_gate(.c(A1), .a(Y3), .b(Y2));
or_gate(.c(A0), .a(Y1), .b(w1));```

Hence, the Verilog code for the priority encoder in structural style is:

```module or_gate(c,a,b);
input a,b;
output c;
assign c = a|b;
endmodule

module not_gate(f,e);
input e;
output f;
assign f = ~e;
endmodule

module and_gate(z,x,y);
input x,y;
output z;
assign z = x&y;
endmodule

module priority_encoder_struct(A0,A1,Y0,Y1,Y2,Y3);```
```input Y0, Y1, Y2, Y3;
output A0,A1;

not_gate u1(.f(y2bar), .e(y2));
and_gate u2(.z(w1), .x(y2bar), .y(y1));
or_gate(.c(A1), .a(Y3), .b(Y2));
or_gate(.c(A0), .a(Y1), .b(w1));

endmodoule```

## Testbench

testbench is an HDL module that is used to test another module, called the device under test (DUT). The test bench contains statements to apply inputs to the DUT and, ideally, to check that the correct outputs are produced. The input and desired output patterns are called test vectors.

Let’s see the test bench for the priority encoder:

```module PriorityEncoder_Test;
//Reg and Wire declarations
reg [3:0] y;
wire [1:0] a;

// Instantiate the Unit Under Test (UUT)
priority_encoderbehave uut (.Y(y), .A(a));
initial
begin
// Initialize Inputs
Y = 0;
// Wait 100 ns for global reset to finish
#100;
// apply test vectors

#10 Y = 4'b0000;
#10 Y = 4'b1000;
#10 Y = 4'b0100;
#10 Y = 4'b0010;
#10 Y = 4'b0001;
#10 Y = 4'b1010;
#10 Y = 4'b1111;
end
initial begin
\$monitor("time=",\$time,, "D=%b : Y=%b V=%b",D,Y,V);
end
endmodule```

## RTL Schematic

Here’s how the RTL Schematic will look if we peek into the elaborate design of the behavioral model of the Priority Encoder.