Encoder using – Verilog

Encoders are digital circuits that are used to encode data, and convert human understandable data to machine understandable data.

A simple example is ASCII encoder, which converts the key pressed on the key board to its corresponding, machine understandable, code.

Encoders are very useful in digital circuits, from pocket calculators to keyboards and much more.

Here we are going to build a simple “priority encoder” using Verilog.

Block diagram
<p value="<amp-fit-text layout="fixed-height" min-font-size="6" max-font-size="72" height="80">The realization of encoder is as simple as it looks. But first we need to understand it in terms of truth table and then minimize the logic function. After that we will have the minimalistic logic to implement.The realization of encoder is as simple as it looks. But first we need to understand it in terms of truth table and then minimize the logic function. After that we will have the minimalistic logic to implement.

D7D6D5D4D3D2D1D
10000000
01000000
00100000
00010000
00001000
00000100
00000010
00000001
INPUTS
Y2Y1Y0
111
110
101
100
011
010
001
000
OUTPUTS

The above is the respective outputs produced by the encoder when any one of the lines is kept high.

The above design can generate error when there are more than one lines that are kept high. This is the major drawback of a simple encoder.

In order to prevent this error, we can introduce priority of inputs. This can be achieved if we discard a Logic High input after one is received in the priority order.

This can be simply understood by redrawing the Truth Table.

D7D6D5D4D3D2D1D0
1XXXXXXX
01XXXXXX
001XXXXX
0001XXXX
00001XXX
000001XX
0000001X
00000001
INPUTS
Y2Y1Y0
111
110
101
100
011
010
001
000
OUTPUTS

This above method has an advantage over the simple encoder, that it gives priority order to the input lines. Thus, if more than two lines are high, only the one with highest priority will be considered.

Now writing Code for this is fairly simple:

Code :

// the-tech-social
// Priority Encoder
// this is a 8 to 3 decoder => with priority enabled
module priority_encoder(
    input wire[7:0] in, // input given
    input wire enable, //chip enable => active high
    output reg [2:0] y // encoded output
    );
	
    always@ * begin
       if (!enable)
         y[2:0] = 4'h0;
       else
         casez(in)
            8'b1???????: y = 3'b111; // d7
            8'b01??????: y = 3'b110; // d6
            8'b001?????: y = 3'b101; // d5
            8'b0001????: y = 3'b100; // d4
            8'b00001???: y = 3'b011; // d3
            8'b000001??: y = 3'b010; // d2 
            8'b0000001?: y = 3'b001; // d1
            8'b00000001: y = 3'b000; // d0
            default: y = 3'b111;     // default is highest priority => d7
	 endcase
    end
endmodule

You can see that I have also added an active high enable in the above code for chip enable. So, when the enable is low no output is received.

RTL view:

The following RTL view is generated using this code,

Generated using Xilinx ISE

Testbench:

Yes, after RTL generation we generally try to figure out a testbench. But since we have already tried a decoder, why not try to link these together.

If you are wondering where is the decoder, please take a look here: https://techno10.tech.blog/2020/12/18/decoder-using-verilog/

Now then, if we need to test the encoder, we can give the inputs at the encoder end and when the output is generated, we can get these to connect to the inputs of the decoder, which in turn will generate the input that we first choose to give in.

What I mean can be shown using the below code:

// the-tech-social
// Test_encoder module
// input => encoder => decoder => output
module Test_encoder (
    input wire[7:0] in, // input given
    input wire enable, //chip enable => active high
    output wire [7:0] out 
);

    wire [2:0] inter;
    // 8to3 encoder module instantiation
    priority_encoder e1(.in(in), .enable(enable), .y(inter));
    // 3to8 decoder module instantiation 
    Decoder d1(.din(inter), .enable(~enable), .dout(out));
    
endmodule

We can see that the intermediate wire “inter” that stores the value of the encoder is then given as the input to the decoder. Also, the enable is connected “inverted” with the decoder since it is active low and “normally” with the encoder since it is active high.

Just remember that we have used 8to3 encoder and 3to8 decoder here to achieve the objective.

This can also be seen in the below RTL view of the module.

Encoder-Decoder test module

Now we can write a test bench to this and expect the output to be the input given as simple as that.

Code for test bench:

// the-tech-social
// Test_encoder_tb
// Testbench for Test_encoder
module Test_encoder_tb;
    reg [7:0] in;
    reg enable;
    wire [7:0] out;

    // initializing the design
    Test_encoder t1(in, enable, out);

    integer i;

    initial enable = 1'b1;

    initial begin
        in = 00000001;
        i = 0;
        #100;
        for (i = 0; i < 8; i=i+1) begin
           in = in<<1;
           #100; 
        end
    end
endmodule

This sure is fun, and we can see the output following the input in the stimulation waveform.

Stimulation:

Here, we can observe that the last input is ‘00000000’ yet the output is ‘10000000’. This is something I will let you figure out by yourself, and fix so that you can have a proper understanding of the encoder and decoder that we have used here.

So, now we have a encoder and a circuit to test its functionality.

Great!!!😎😎

Decoder Using – Verilog

3 to 8 Decoder using Verilog Programming

Content to be covered :

  • Decoder -> what is it?
  • Truth Table
  • Enable logic
  • Verilog Code
  • RTL view
  • Testbench
  • Stimulation

1. Decoder -> what is it?

A decoder is a digital circuit, that helps convert an given n coded input to a 2n outputs.

A decoder various applications such as data multiplexing and data demultiplexing, seven segment displays, and as address decoders for memory and port-mapped I/O.

There are few different types of decoders. For example, the above is 1-of-n type of binary decoder, meaning that when, an input is given only 1 or none of the output is activated.

A binary decoder is usually implemented as a standalone IC or as a part of more complex ICs.

So, if there are N inputs, the decoder will produce a maximum of 2n outputs. Thus, if we have 3-bit input we will have 23 = 8-bit output. In Verilog Coding, of a particular combinational circuit it is necessary to know the number of input/output a particular chip may require.

Since, we now understand the concept behind the decoder, we should start with the logic oriented part.

2. Truth Table

Any digital circuit can be realized using Truth Table. This is the beauty of digital Electronics. Also using this table to simplify the logic of the design we initially thought off.

DINDOUT
000 00000001
001 00000010
010 00000100
011 00001000
100 00010000
101 00100000
110 01000000
111 10000000
Truth Table for 3 to 8 decoder

3. Enable Logic

Yes, the theoretical part of the design is almost over with the understanding of the enable input, which is the driver of the combinational logic. Take a look at the transformed truth table

EnableDINDOUT
1XXX00000000
000000000001
000100000010
001000000100
001100001000
010000010000
010100100000
011001000000
011110000000
Truth Table for 3 to 8 decoder with enable

You can see that the design modifies in a sense that if the enable is logic 0 => the output becomes zero no matter the input. Thus, this enable can be used as a switch by many devices in order to keep this device “on” only in the time of need. Also, this type of enabling is called active low, since the chip gets activated when the enable turns low(i.e. enable = 0).

4. Verilog Code

Okay so without further delay, here’s the code for decoder.

Also here is the link to my git repo -> https://github.com/nirbhay12345/chipDesign/Decoder

module Decoder ( // 3 to 8 decoder
    input [2:0] din, // input signal
    input enable, // chip enable signal => active low
    output reg [7:0] dout // selected output
);

    // main logic
    always @* begin
        if (enable)
            dout[7:0] <= 8'h00;
        else
            case (din[2:0])
                3'b000 : dout[7:0] <= 8'h01;
                3'b001 : dout[7:0] <= 8'h02;
                3'b010 : dout[7:0] <= 8'h04;
                3'b011 : dout[7:0] <= 8'h08;
                3'b100 : dout[7:0] <= 8'h10;
                3'b101 : dout[7:0] <= 8'h20;
                3'b110 : dout[7:0] <= 8'h40;
                3'b111 : dout[7:0] <= 8'h80;
                //default is necessary to avoid any latchs
                default: dout[7:0] <= 8'h00; 
            endcase
    end

endmodule

5. RTL view

The design thus converted into a simple combinational logic. Also, you can always convert it into a parametric form in order to scale things up. But that’s up to you to decide.

Generated using Xilinx ISE

6. Testbench

Here is the testbench :

module Decoder_tb;
    reg [2:0] din;
    reg enable;
    wire [7:0] dout;

    // instantiate the design block
    Decoder d1(din, enable, dout);

    integer i;

    initial begin
        enable = 1'b1;
        din = 3'b000;
        i = 0;
        #100
        enable = 1'b0;
        for (i = 0; i < 8; i=i+1) begin
            din = din + 3'b001;
            #100;
        end
    end

endmodule

The above testbench probably includes all the possibility of the design and thus completes our design. Just one thing to Go -> Stimulation.

7. Stimulation

Time to test and observe our design.

Great going !! We now have a decoder of our own! 😎