matteof93
matteof93

Reputation: 53

VHDL Data Flow description of Gray Code Incrementer

I am trying to write the VHDL code for a Gray Code incrementer using the Data Flow description style. I do not understand how to translate the for loop I used in the behavioral description into the Data Flow description. Any suggestion?

This is my working code in behavioral description

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity graycode is
    Generic (N: integer := 4);
     Port ( gcode : in  STD_LOGIC_VECTOR (N-1 downto 0);
           nextgcode : out  STD_LOGIC_VECTOR (N-1 downto 0));
end graycode;

architecture Behavioral of graycode is
begin

process(gcode)

    variable bcode : STD_LOGIC_VECTOR(N-1 downto 0);
    variable int_bcode : integer;

begin

    for i in gcode'range loop
        if(i < gcode'length - 1) then
            bcode(i) := gcode(i) XOR bcode(i+1);
            else
                bcode(i) := gcode(i);
        end if;
    end loop;

    int_bcode := to_integer(unsigned(bcode));
    int_bcode := int_bcode + 1;
    bcode := std_logic_vector(to_unsigned(int_bcode, N));

    for i in gcode'range loop
        if(i < gcode'length - 1) then
            nextgcode(i) <= bcode(i) XOR bcode(i+1);
            else
                nextgcode(i) <= bcode(i);
        end if;
    end loop;

end process;
end Behavioral;

Upvotes: 0

Views: 609

Answers (2)

user1155120
user1155120

Reputation:

Dataflow means constructed of concurrent statements using signals.

That means using generate statements instead of loops. The if statement can be an if generate statement with an else in -2008 or for earlier revisions of the VHDL standard two if generate statements with the conditions providing opposite boolean results for the same value being evaluated.

It's easier to just promote the exception assignments to their own concurrent signal assignments:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity graycode is
    generic (N: natural := 4); -- CHANGED negative numbers wont be interesting
     port ( 
         gcode:      in   std_logic_vector (N - 1 downto 0);
         nextgcode:  out  std_logic_vector (N - 1 downto 0)
    );
end entity graycode;

architecture dataflow of graycode is
    signal int_bcode:     std_logic_vector (N - 1 downto 0);  -- ADDED
    signal bcode:         std_logic_vector (N - 1 downto 0);  -- ADDED
begin

    int_bcode(N - 1) <= gcode (N - 1);
TO_BIN: 
    for i in N - 2 downto 0 generate
        int_bcode(i) <= gcode(i) xor int_bcode(i + 1);
    end generate;

    bcode <= std_logic_vector(unsigned(int_bcode) + 1);

    nextgcode(N - 1) <= bcode(N - 1);
TO_GRAY:
    for i in N - 2 downto 0 generate
        nextgcode(i) <= bcode(i) xor bcode(i + 1);
    end generate;

end architecture dataflow;

Each iteration of a for generate scheme will elaborate a block statement with an implicit label of the string image of i concatenated on the generate statement label name string.

In each of these blocks there's a declaration for the iterated value of i and any concurrent statements are elaborated into those blocks.

The visibility rules tell us that any names not declared in the block state that are visible in the enclosing declarative region are visible within the block.

These mean concurrent statements in the block are equivalent to concurrent statement in the architecture body here with a value of i replaced by a literal equivalent.

The concurrent statements in the generate statements and architecture body give us a dataflow representation.

And with a testbench:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity graycode_tb is
end entity;

architecture foo of graycode_tb is
    constant N:         natural := 4;
    signal gcode:       std_logic_vector (N - 1 downto 0);
    signal nextgcode:   std_logic_vector (N - 1 downto 0);
    signal bcode:       std_logic_vector (N - 1 downto 0);
begin
DUT:
    entity work.graycode
        generic map ( N => N)
        port map (
            gcode => gcode,
            nextgcode => nextgcode
        );

STIMULi:
    process
    variable gv:        std_logic_vector (N - 1 downto 0);
    variable bv:        std_logic_vector (N - 1 downto 0);
    begin
        wait for 10 ns;
        for i in 0 to 2 ** N - 1 loop  

            bv := std_logic_vector(to_unsigned( i, bv'length));
            gv(N - 1) := bv (N - 1);   
            for i in N - 2 downto 0 loop
                gv(i) := bv(i) xor bv(i + 1);
            end loop;
            gcode  <= gv;
            bcode  <= bv;
            wait for 10 ns;
        end loop;
        wait;
    end process;
end architecture;

We can see the effects of incrementing int_bcode:

graycode_tb.png

Upvotes: 0

EML
EML

Reputation: 10280

'Dataflow' means 'like it would look in a circuit diagram'. In other words, the flow of data through a real circuit, rather than a high-level algorithmic description. So, unroll your loops and see what you've actually described. Start with N=2, and draw out your unrolled circuit. You should get a 2-bit input bus, with an xor gate in it, followed by a 2-bit (combinatorial) incrementor, followed by a 2-bit output bus, with another xor gate, in it. Done, for N=2.

Your problem now is to generalise N. One obvious way to do this is to put your basic N=2 circuit in a generate loop (yes, this is dataflow, since it just duplicates harwdare), and extend it. Ask in another question if you can't do this.

BTW, your integer incrementor is clunky - you should be incrementing an unsigned bcode directly.

Upvotes: 0

Related Questions