Coding pipeline in VHDL – Part 1

Contents of this article:
1) introducing and defining of Pipeline.
2)D flip-flop(DFF) as a basic memory element
3)implementing DFF in VHDL and explaining how it helps in pipeline.
4)example with code on: how to pipeline full adders with pipeline.
5)example with code on: how to implement a Multiplier(using full adders) with pipeline

Introduction to Pipeline:
Here I present a basic and shallow description of the concept of Pipeline, since the goal of this post is to help transforming the design from paper to code!
in hardware implementation of a set of tasks accomplished by a logic function(i.e adding the numbers from 1 to 10), many times we face the problem of having parts in the circuit functioning while the other parts are not doing anything. Obviously, in this situation, the “resting” parts could be harnessed for accomplishing the next task, that means a part of the circuit is working on a current task and the other part is working on the next task in row. this situation is called pipeline.

VHDL basic concepts :
assuming that the reader already has a basic knowledge of the fundemental concepts of the hardware describing language of VHDL, we will face the terms:
1)signal, signal types: std_logic and std_logic_vector
2)entity and architecture
nothing more com;ex than that!

dffwaveform
the output Q changes only when the CLOCK edge rises.

D-flip flop(DFF):
a DFF is the basic memory element in logic circuits, and here we’ll harness it in order to help implementing the pipeline.
Assuming having a clock and input data, then what the DFF does is getting the input gata when the clock rises and giving us back the input data as an output when the clock rises again. the following images gives a thorough understanding of its functionality:
dff

coding a DFF in VHDL:
The coding is very straightforward: we need a Clok input signal as well as the Reset signal and the input data itself. The output will be a signal as well:

library ieee;
use ieee.std_logic_1164.all;
-- defining a register(normal DFF - 1 bit):
entity reg is
 port(
 D : in std_logic;
 CLK : in std_logic;
 RSTn : in std_logic;
 Q : out std_logic
 );
end entity;
architecture behavior of reg is
begin
 process(CLK, RSTn)
 begin
 if RSTn = '0' then Q <= '0';
 elsif rising_edge(CLK)then Q <= D;
 end if; 
 end process;
end architecture;
---------------------end of register------------------------------

 Example 1: Implementing Piped Full Adder with VHDL:

Assuming you already know how a Full adder works and how it's implemented using VHDL. Here is the waveform that describes its functionality.
Assuming you already know how a Full adder works and how it’s implemented using units of half adders. Here is the waveform that describes its functionality.(click the image to enlarge).


We need to add two 4 bit numbers: (A0A1A2A3)+(B0B1B2B3) using the basic blocks of full adders:
for that matter, it’s preferable to use 4 full adders and cascade them in row:

reference: http://macao.communications.museum. in the diagram above: P,Q are the bits we want to add in a sngle basc unit of FullAdder, CI is the carry in, CO is the carry out, S is the sum product.

As the above diagram suggests, P0,Q0 are the 2 bits of the first number.
Our next objective is to pipeline the circuit above:

the green lines represents the registers and the red lines are the guide tool for determining the distribution of the registers

Now that we know the overview of the whole circuit and the exact place of each register, we should analyse how to approach such a thing:
pay attention that:
1) the outputs of the circuit: S0,S1,S2,S3,S4: each output goes through a different number of registers, i.e S0 goes through 4 registers while S1 goes through 3 registers..
2)same analysis of the outputs applies for the inputs as well: A1,B1,A2,…
3)between each Cin and Cout there is a register.
The next step is to put the building stones of the VHDL code :
defining the signals:
1)Each signal that goes through multiple registers(i.e S0), we define a signal of type std_logic_vector, other signal that goes through one register or no registers at all, we’ll define them as std_logic.
2)
The Cin/Cout signals should be treated differently, since they pass between the units, in other words, the Cout of the first full adder is the Cin for the next full adder. In our case, we define a vector of length 4 for the Cout and a vector of length 3 for Cin(because the last FA Cout signal does not enter to another FA Cin).
3)Since the 2 numbers we are adding are formed of 4 bits, then the 2 signals that describe those 2 numbers, should be of type std_logic_vector, of length 4.
code for the signals:

signal tmp_cout : std_logic_vector(3 downto 0);
signal tmp_cin : std_logic_vector(2 downto 0);
signal tmp_S0 : std_logic_vector(3 downto 0);
signal tmp_S1 : std_logic_vector(2 downto 0);
signal tmp_S2 : std_logic_vector(1 downto 0);
signal tmp_S3 : std_logic;
signal tmp_A1 : std_logic;
signal tmp_B1 : std_logic;
signal tmp_A2 : std_logic_vector(1 downto 0);
signal tmp_B2 : std_logic_vector(1 downto 0);
signal tmp_A3 : std_logic_vector(2 downto 0);
signal tmp_B3 : std_logic_vector(2 downto 0);

Next, we define the port map of the Full Adders (components)
*later in the post, I will show how to implement a full adder and use it as a component

FA_0: FA port map(Cin=>Cin,A=>A(0),B=>B(0),S=>tmp_S0(0),Cout=>tmp_cout(0));

FA_1: FA port map(Cin=>tmp_cin(0),A=>tmp_A1,B=>tmp_B1,S=>tmp_S1(0),Cout=>tmp_cout(1));

FA_2: FA port map(Cin=>tmp_cin(1),A=>tmp_A2(1),B=>tmp_B2(1),S=>tmp_S2(0),Cout=>tmp_cout(2));

FA_3: FA port map(Cin=>tmp_cin(2),A=>tmp_A3(2),B=>tmp_B3(2),S=>tmp_S3,Cout=>tmp_cout(3));

Remember all the green lines(registers) in the circuit diagram above? and still also remember all the signals like tmp_S0 and tmp_cout and even tmp_B1,…?
those are registers, which means, we should use the register/D-flip flop component we implemented earlier and write the port map for each one and one of those signals!
WARNING: the following process involves a lot “copy/paste” of code, be careful with the indexes!

reg_s0_0: reg port map(tmp_S0(0),CLK,RSTn,tmp_S0(1));
reg_s0_1: reg port map(tmp_S0(1),CLK,RSTn,tmp_S0(2));
reg_s0_2: reg port map(tmp_S0(2),CLK,RSTn,tmp_S0(3));
reg_s0_3: reg port map(tmp_S0(3),CLK,RSTn,S(0));

reg_s1_0: reg port map(tmp_S1(0),CLK,RSTn,tmp_S1(1));
reg_s1_1: reg port map(tmp_S1(1),CLK,RSTn,tmp_S1(2));
reg_s1_2: reg port map(tmp_S1(2),CLK,RSTn,S(1));

reg_s2_0: reg port map(tmp_S2(0),CLK,RSTn,tmp_S2(1));
reg_s2_1: reg port map(tmp_S2(1),CLK,RSTn,S(2));

reg_s3_1: reg port map(tmp_S3,CLK,RSTn,S(3));

reg_cout0: reg port map(tmp_cout(0),CLK,RSTn,tmp_cin(0));
reg_cout1: reg port map(tmp_cout(1),CLK,RSTn,tmp_cin(1));
reg_cout2: reg port map(tmp_cout(2),CLK,RSTn,tmp_cin(2));
reg_cout3: reg port map(tmp_cout(3),CLK,RSTn,Cout);

reg_A1: reg port map(A(1),CLK,RSTn,tmp_A1);
reg_B1: reg port map(B(1),CLK,RSTn,tmp_B1);

reg_A2_0: reg port map(A(2),CLK,RSTn,tmp_A2(0));
reg_B2_0: reg port map(B(2),CLK,RSTn,tmp_B2(0));
reg_A2_1: reg port map(tmp_A2(0),CLK,RSTn,tmp_A2(1));
reg_B2_1: reg port map(tmp_B2(0),CLK,RSTn,tmp_B2(1));

reg_A3_0: reg port map(A(3),CLK,RSTn,tmp_A3(0));
reg_B3_0: reg port map(B(3),CLK,RSTn,tmp_B3(0));
reg_A3_1: reg port map(tmp_A3(0),CLK,RSTn,tmp_A3(1));
reg_B3_1: reg port map(tmp_B3(0),CLK,RSTn,tmp_B3(1));
reg_A3_2: reg port map(tmp_A3(1),CLK,RSTn,tmp_A3(2));
reg_B3_2: reg port map(tmp_B3(1),CLK,RSTn,tmp_B3(2));

All is left now to do is
1)To implement the Full adder component.
2)write the entity and architecture for every component used in the code including the piped adder.
3)connect all the pieces of the code(we already wrote above) together.
in the following code section, I will do all of the 3 above!

library ieee;
use ieee.std_logic_1164.all;

entity reg is
 port(D,CLK,RSTn: in std_logic;
 Q: out std_logic);
end entity;

architecture behaviour of reg is
begin
	process(CLK,RSTn)
	begin
		 if RSTn = '0' then
			Q <= '0';
		 elsif rising_edge(clk) then
			Q <= D;
		 end if;
	end process;
end architecture;

library ieee;
use ieee.std_logic_1164.all;

entity FA is
PORT (Cin,A,B: IN STD_LOGIC ;
 Cout,S: OUT STD_LOGIC ) ;
END entity;

ARCHITECTURE behaviour OF FA is
begin
	S <= A XOR B XOR Cin ;
	Cout <= (A AND B) OR (Cin AND A) OR (Cin AND B) ; 
end architecture;
 
--piped adder: 
library ieee; 
use ieee.std_logic_1164.all; 

entity PipedAdder is port(A,B: in std_logic_vector(3 downto 0);  
CLK,RSTn,Cin : in std_logic  
Cout: out std_logic;  
S: std_logic_vector(3 downto 0)); 
end entity; 

architecture behaviour of reg is 
component FA PORT (Cin,A,B: IN STD_LOGIC ;  Cout,S: OUT STD_LOGIC ) ; 
end component; 

component reg port(D,CLK,RSTn: in std_logic;  Q: out std_logic); 
end component; 
reg_s0_0: reg port map(tmp_S0(0),CLK,RSTn,tmp_S0(1)); 
reg_s0_1: reg port map(tmp_S0(1),CLK,RSTn,tmp_S0(2)); 
reg_s0_2: reg port map(tmp_S0(2),CLK,RSTn,tmp_S0(3)); 
reg_s0_3: reg port map(tmp_S0(3),CLK,RSTn,S(0)); 
reg_s1_0: reg port map(tmp_S1(0),CLK,RSTn,tmp_S1(1)); 
reg_s1_1: reg port map(tmp_S1(1),CLK,RSTn,tmp_S1(2)); 
reg_s1_2: reg port map(tmp_S1(2),CLK,RSTn,S(1)); 
reg_s2_0: reg port map(tmp_S2(0),CLK,RSTn,tmp_S2(1)); 
reg_s2_1: reg port map(tmp_S2(1),CLK,RSTn,S(2)); 
reg_s3_1: reg port map(tmp_S3,CLK,RSTn,S(3)); 
reg_cout0: reg port map(tmp_cout(0),CLK,RSTn,tmp_cin(0)); 
reg_cout1: reg port map(tmp_cout(1),CLK,RSTn,tmp_cin(1)); 
reg_cout2: reg port map(tmp_cout(2),CLK,RSTn,tmp_cin(2)); 
reg_cout3: reg port map(tmp_cout(3),CLK,RSTn,Cout); 
reg_A1: reg port map(A(1),CLK,RSTn,tmp_A1); 
reg_B1: reg port map(B(1),CLK,RSTn,tmp_B1);
reg_A2_0: reg port map(A(2),CLK,RSTn,tmp_A2(0)); 
reg_B2_0: reg port map(B(2),CLK,RSTn,tmp_B2(0)); 
reg_A2_1: reg port map(tmp_A2(0),CLK,RSTn,tmp_A2(1)); 
reg_B2_1: reg port map(tmp_B2(0),CLK,RSTn,tmp_B2(1)); 
reg_A3_0: reg port map(A(3),CLK,RSTn,tmp_A3(0)); 
reg_B3_0: reg port map(B(3),CLK,RSTn,tmp_B3(0)); 
reg_A3_1: reg port map(tmp_A3(0),CLK,RSTn,tmp_A3(1)); 
reg_B3_1: reg port map(tmp_B3(0),CLK,RSTn,tmp_B3(1)); 
reg_A3_2: reg port map(tmp_A3(1),CLK,RSTn,tmp_A3(2)); 
reg_B3_2: reg port map(tmp_B3(1),CLK,RSTn,tmp_B3(2)); 
begin 
FA_0: FA port map(Cin=>Cin,A=>A(0),B=>B(0),S=>tmp_S0(0),Cout=>tmp_cout(0));
FA_1: FA port map(Cin=>tmp_cin(0),A=>tmp_A1,B=>tmp_B1,S=>tmp_S1(0),Cout=>tmp_cout(1));
FA_2: FA port map(Cin=>tmp_cin(1),A=>tmp_A2(1),B=>tmp_B2(1),S=>tmp_S2(0),Cout=>tmp_cout(2));
FA_3: FA port map(Cin=>tmp_cin(2),A=>tmp_A3(2),B=>tmp_B3(2),S=>tmp_S3,Cout=>tmp_cout(3));

-- EDIT: 29 Apr. 2017 - Thanks to sneha and Isabella comments for- 
--pointing the unnecessary duplication of the commented code bellow.

--reg_s0_0: reg port map(tmp_S0(0),CLK,RSTn,tmp_S0(1));
--reg_s0_1: reg port map(tmp_S0(1),CLK,RSTn,tmp_S0(2));
--reg_s0_2: reg port map(tmp_S0(2),CLK,RSTn,tmp_S0(3));
--reg_s0_3: reg port map(tmp_S0(3),CLK,RSTn,S(0));

--reg_s1_0: reg port map(tmp_S1(0),CLK,RSTn,tmp_S1(1));
--reg_s1_1: reg port map(tmp_S1(1),CLK,RSTn,tmp_S1(2));
--reg_s1_2: reg port map(tmp_S1(2),CLK,RSTn,S(1));

--reg_s2_0: reg port map(tmp_S2(0),CLK,RSTn,tmp_S2(1));
--reg_s2_1: reg port map(tmp_S2(1),CLK,RSTn,S(2));

--reg_s3_1: reg port map(tmp_S3,CLK,RSTn,S(3));

--reg_cout0: reg port map(tmp_cout(0),CLK,RSTn,tmp_cin(0));
--reg_cout1: reg port map(tmp_cout(1),CLK,RSTn,tmp_cin(1));
--reg_cout2: reg port map(tmp_cout(2),CLK,RSTn,tmp_cin(2));
--reg_cout3: reg port map(tmp_cout(3),CLK,RSTn,Cout);

--reg_A1: reg port map(A(1),CLK,RSTn,tmp_A1);
--reg_B1: reg port map(B(1),CLK,RSTn,tmp_B1);

--reg_A2_0: reg port map(A(2),CLK,RSTn,tmp_A2(0));
--reg_B2_0: reg port map(B(2),CLK,RSTn,tmp_B2(0));
--reg_A2_1: reg port map(tmp_A2(0),CLK,RSTn,tmp_A2(1));
--reg_B2_1: reg port map(tmp_B2(0),CLK,RSTn,tmp_B2(1));

--reg_A3_0: reg port map(A(3),CLK,RSTn,tmp_A3(0));
--reg_B3_0: reg port map(B(3),CLK,RSTn,tmp_B3(0));
--reg_A3_1: reg port map(tmp_A3(0),CLK,RSTn,tmp_A3(1));
--reg_B3_1: reg port map(tmp_B3(0),CLK,RSTn,tmp_B3(1));
--reg_A3_2: reg port map(tmp_A3(1),CLK,RSTn,tmp_A3(2));
--reg_B3_2: reg port map(tmp_B3(1),CLK,RSTn,tmp_B3(2));

end architecture;

This is the code for the first example!

The next example is going to be more complex and more interesting:
a multiplier that multiply  2 numbers: one is 2 bit and the other is 4 bit.
Obviously, the idea is the same, but no wonder it’s gonna be more big, therefore, I will be dedicating another post for it soon!
Hope this helps you grasp the idea of coding a pipeline circuit, if there is something you didn’t quit understand, please leave a comment bellow, I will try my best to give you the best answer!

~ to be continued!

6 thoughts on “Coding pipeline in VHDL – Part 1

  1. Hello, very good example of pipeline. I just have some doubt, why you copy two times the port maps for the register? and why one of it is before the “begin”?

    thanks for your help

    1. Thank you Isabella for your reply!
      could you please specify the exact code snippet you’re referring to?
      anyway, the ‘port map’ are being copied due to the fact that a certain output it few bit wide..for example:

      reg_cout0: reg port map(tmp_cout(0),CLK,RSTn,tmp_cin(0));
      reg_cout1: reg port map(tmp_cout(1),CLK,RSTn,tmp_cin(1));
      reg_cout2: reg port map(tmp_cout(2),CLK,RSTn,tmp_cin(2));
      reg_cout3: reg port map(tmp_cout(3),CLK,RSTn,Cout);

      cout here is 4-bit so you need 4 registers: reg_cout0, .., reg_cout3.

      i hope this helps! please write back if you have furthers questions.

  2. i have the same doubt as isabella, its not clear in your reply. Why have u done portmapping twice i.e one before the begin and one after

    1. Sneha and Isabella,
      Looking at this now, I cannot remember why I did this. Maybe you are right, we don’t really need double mapping.
      As it was long time ago since the code was written, I lost the original project to check this issue, and could be that I mistakenly copied the code twice. The ‘algorithm’ behind the code works and performs what has been described.
      Please, if you find out that the duplication is unnecessary, let me know, and i’ll edit as well as credit you in the post.

      Regards

      1. yes the duplication is unnecessary. I guess you copied the portmapping instead of defining the signals. Thank you it helped a lot

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: