VHDL coding tips and tricks: VHDL: Parallel In Serial Out Register with Testbench

Thursday, September 9, 2010

VHDL: Parallel In Serial Out Register with Testbench

    In this article I want to share the VHDL code for a 4 bit parallel in serial out shift register. Its known as PISO in short form. The shift register can be loaded with any chosen 4 bit value and thereafter in every clock cycle a bit is shifted out from the output port.

    To make it interesting, I have written two different versions of the code - one in behavioral level and in another in gate level. This will help you understand practically, how these two models are different. 

    In gate level modeling the entity is implemented in terms of logic gates and their interconnections. Designs at this level are similar to describing a circuit in terms of a gate level logic diagram.

    In Behavioral level(Algorithmic level) modeling an entity is implemented in terms of the desired design algorithm without the concern for the hardware circuit elements. Designing at this level is the highest abstraction level provided by VHDL.

    Lets look at the Behavioral level model for PISO first. Its much easier to understand than the gate level, I believe.

PISO - Behavioral Level Model:


--library declaration.
library ieee;
use ieee.std_logic_1164.all;

--parallel in serial out shift register
entity piso is
port(Clk : in std_logic;  --Clock signal
    parallel_in : in std_logic_vector(3 downto 0);  --4 bit parallel load
    load : in std_logic;  --active high for loading the register
    serial_out : out std_logic  --output bit. 
    );
end piso;

architecture behavioral of piso is

signal load_value : std_logic_vector(3 downto 0) := "0000";

begin

process(Clk)
begin
if(rising_edge(Clk)) then
    if(load ='0') then  --do the serial right shifting here.
        serial_out <= load_value(3); --MSB goes to output port
        load_value(3) <= load_value(2);
        load_value(2) <= load_value(1);
        load_value(1) <= load_value(0);
        load_value(0) <= '0';  --'0' is loaded to LSB
    else   --load the registers with a new value to shift.
        load_value <= parallel_in;
    end if;
end if;
end process;

end behavioral;

Testbench for the PISO:


library ieee;
use ieee.std_logic_1164.all;

--testbench has empty entity
entity tb_piso is
end entity tb_piso;

architecture behavioral of tb_piso is

signal Clk,load,serial_out : std_logic := '0';
signal parallel_in :std_logic_vector(3 downto 0) := "0000";
constant Clk_period : time := 10 ns;

begin

--entity instantiation with named association port mapping
piso_uut: entity work.piso
    port map(Clk => Clk,
        parallel_in => parallel_in,
        load => load,
        serial_out => serial_out);

--generate clock
Clk_generation: process
begin
    wait for Clk_period/2;
    Clk <= not Clk; --toggle clock when half of clk_period is over
end process;

stimulus: process
begin 
    wait for Clk_period;
    parallel_in <= "1011";  wait for Clk_period;
    load <= '1';   wait for Clk_period;
    load <= '0';   wait for Clk_period*5;
    parallel_in <= "1001";  wait for Clk_period;
    load <= '1';   wait for Clk_period;
    load <= '0';   wait for Clk_period*5;
    wait;  --testing done. wait endlessly
end process;

end behavioral;

Lets take a look at the simulation waveform from modelsim.

Simulation Waveform from Modelsim:


piso simulation waveform from modelsim vhdl

Post Synthesis Schematic from Xilinx Vivado:


technology schematic from xilinx vivado for piso

PISO - Gate Level Model:


    Looking at the first code, you can see that the it is written using if.. else.. statements. We haven't used any digital circuit elements like flip-flops, gates or registers. The code describes what we want, in a language similar to a high level language like C (though there are lot of differences between C and VHDL).

Now let us look at the Gate level code:

--library declaration.
library ieee;
use ieee.std_logic_1164.all;

--parallel in serial out shift register
entity piso is
port(Clk : in std_logic;  --Clock signal
    parallel_in : in std_logic_vector(3 downto 0);  --4 bit parallel load
    load : in std_logic;  --active high for loading the register
    serial_out : out std_logic  --output bit. 
    );
end piso;

architecture gate_level of PISO is

signal D1,D2,D3,D4,Q1,Q2,Q3,Q4 : std_logic := '0';
signal load_value : std_logic_vector(3 downto 0) := "0000";

begin

load_value <= parallel_in;
serial_out <= Q4;

--entity instantiation of the D flipflop.It is instantiated 4 times to make a 4 bit register.
FDRSE11 : entity work.FDRSE1    
    port map (
        Clk => Clk,
        ce => '1',
        reset => '0',
        D => D1,
        set => '0',
        Q => Q1);  --MSB

FDRSE22 : entity work.FDRSE1
port map (
    Clk => Clk,
    ce => '1',
    reset => '0',
    D => D2,
    set => '0',
    Q => Q2);

FDRSE33 : entity work.FDRSE1
    port map (
        Clk => Clk,
        ce => '1',
        reset => '0',
        D => D3,
        set => '0',
        Q => Q3);

FDRSE44 : entity work.FDRSE1  
    port map (
        Clk => Clk,
        ce => '1',
        reset => '0',
        D => D4,
        set => '0',
        Q => Q4);   --LSB

--The D inputs of the flip flops are controlled with the load input.
--Two AND gates with a OR gate is used for this.
D1 <= load_value(3) and load;
D2 <= (load_value(2) and load) or (Q1 and not(load));
D3 <= (load_value(1) and load) or (Q2 and not(load));
D4 <= (load_value(0) and load) or (Q3 and not(load));

end gate_level;

The FDRSE1 flipflop used in the above code can be copied from an earlier post: Synchronous D Flip-Flop with Testbench.

    We can make the following observations from the code:
  1. The D flipflop itself is written in behavioral level, but that doesnt matter, since its instantiated as a "black box" in the piso entity.
  2. We have used VHDL gate level primitives such as not, and, or etc.. to implement our design.
  3. The flip flop required for implementing the 4 bit register was defined in a separate file and then instantiated in the piso entity. 
  4. We didn't use a "process" statement in the code.
  5. The above code is also an example of Structural level modeling, where we use a hierarchy of entities. For example the D flip flop is considered as a black box from the PISO block's point of view. Once the flip flop (or generally any other module) is designed and verified we can use it any number of times anywhere as part of another design. 

    Another example for structural level coding : 4 bit Synchronous UP counter(with reset) using JK flip-flops. 
    
    Some more examples for gate level modeling: 3 to 8 decoder using basic logic gates and 4 bit ripple carry adder.

Lets take a look at the simulation waveform from modelsim.

Simulation Waveform from Modelsim:


simulation waveform in modelsim of piso vhdl


Post Synthesis Schematic from Xilinx Vivado:


schematic of piso from xilinx vivado vhdl


I hope, by this point, the differences between Behavioral and Gate level modeling is clear to you. Those who have come to the field of FPGAs from a software engineering background, might find it hard to do gate level designs. But it doesn't really matter. Often you can write equally efficient designs using behavioral modelling, if you keep few fundamental facts of hardware designing in mind.

Note:- I have instantiated modules using the "entity instantiation" method. If you are new to this method please read this article, Instantiating components in VHDL.

4 comments:

  1. This is a great website and some fantastic information.

    However every programme I write or compile I seem to have errors! When I compile this one I get
    "ERROR:Simulator:754 - Signal EXCEPTION_ACCESS_VIOLATION received
    ERROR:Simulator:754 - Signal EXCEPTION_ACCESS_VIOLATION received"

    What is it and why do i get it twice?
    I get it when i try and simulate. I am using xilinx 12.3 (I went to 12.3 as I was getting them with 12.2)

    Thanks

    ReplyDelete
  2. Ive solved it, uninstall embassy trust suite from laptop. as per
    http://forums.xilinx.com/t5/Archived-ISE-issues/Any-idea-about-quot-ERROR-Simulator-754-quot/m-p/20835

    Thanks

    ReplyDelete
  3. Thank you very much for your vhdl code and it is very much helpful, also you made it very clear that the difference between the gate level coding and direct vhdl coding.

    Srinivasa Rao

    ReplyDelete
  4. Can someone please help me how to convert VHDL behavioral level file into Gate-level file??

    ReplyDelete