Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

VHDL generics: how to make a port of width log2(generic)

Status
Not open for further replies.

mrothe

Newbie level 3
Joined
Aug 26, 2010
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,310
Suppose I have an entity that has a generic that sets the width of one input. Now I want to have an output that has the minimum width to address each of the input bits.

A 12-bit example follows:

Code:
entity priority_encoder is
    port (
        input : in std_logic_vector(11 downto 0);
        output : out std_logic_vector(3 downto 0)
    );
end priority_encoder;

What I want to do is the following:

Code:
entity priority_encoder_ng is
    generic (
        width : positive;
    );
    port (
        input : in std_logic_vector(width downto 0);
        output : out std_logic_vector(log2(width) downto 0)
    );
end priority_encoder_ng;

(Ok. I want to have "next greater integer of log2(width)", but that would make the pseudo code unnecessary unreadable.)

Is there VHDL syntax that can do this? What happens if the input is only two bits wide? I.e. the output needs to be std_logic instead of std_logic_vector.

If there is no such construct, what would be a good solution to accomplish this task? A second generic that describes the output of the entity and hope that the user instantiates the entity correctly?
 

I think, having two generics for this specifications is the most reasonable method.
Setting both values consistently in the component instantiation is only half the
problem, you also have to supply actual port parameters of correct width. In most
cases, you want to have constants in the instantiating design entity that both
set the parameter width and feed the generics. In constant definition, one could be
derived from the other, e.g.
Code:
constant log_w_par : integer := integer(ceil(log2(real(w_par))));

std_logic_vector(0 downto 0) is a legal VHDL signal definition that solves the problem
of minimum parameter width.
 
  • Like
Reactions: mrothe

    mrothe

    Points: 2
    Helpful Answer Positive Rating
Write your own log 2 function in a package (and with something as useful as log2, you could put it in a utils package you use for every project):

Code:
function log2( i : natural) return integer is
    variable temp    : integer := i;
    variable ret_val : integer := 0; 
  begin					
    while temp > 1 loop
      ret_val := ret_val + 1;
      temp    := temp / 2;     
    end loop;
  	
    return ret_val;
  end function;
 
  • Like
Reactions: mrothe

    mrothe

    Points: 2
    Helpful Answer Positive Rating
Thank you. After some trail & error I came up with the following code:

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;

entity top is
    port (
        clk : in std_logic;
        reset : in std_logic;

        input : in std_logic_vector(7 downto 0); -- 7 = width - 1
        segment : out std_logic_vector(6 downto 0);
        --second_bcd : out std_logic_vector(6 downto 0)
        dp : out std_logic;
        an : out std_logic_vector(3 downto 0)
    );
    constant width : integer := 8;
    constant log_width : integer := integer(ceil(log2(real(width)))); -- 3
end top;

architecture arch of top is
    signal first : std_logic_vector(log_width - 1 downto 0);
    signal second : std_logic_vector(log_width - 1 downto 0);
    signal validity : std_logic_vector(1 downto 0);
begin
    dual_priority_encoder : entity work.dual_priority_encoder
    generic map(input_width => width, output_width => log_width)
    port map(clk => clk, reset => reset, input => input,
             first => first, second => second, validity => validity);

    first_bcd_segment : entity work.bcd
    port map(clk => clk, reset => reset, bcd => first, segment => segment);

    -- second_bcd_segment: entity work.bcd
    -- port map(clk => clk, reset => reset, bcd => second, segment => second_bcd);

    dp <= '1';
    an <= "1110";
end arch;

Code:
-- Standard priority encoder: http://en.wikipedia.org/wiki/Priority_encoder
-- Outputs the binary codes for the first and second highest priority
-- requests.

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

entity dual_priority_encoder is
    generic (
        input_width : positive;
        output_width : positive
    );
    port (
        clk     : in std_logic;
        reset   : in std_logic;

        input   : in std_logic_vector(input_width - 1 downto 0);
        first   : out std_logic_vector(output_width - 1 downto 0);
        second  : out std_logic_vector(output_width - 1 downto 0);

        -- validity:
        -- 00: input is all zero
        -- 01: only one '1' in input, returns this input in `first'.
        -- 10: at least two '1's in input, returns first and second
        --     highest priority in `first' and `second'.
        -- 11: unused
        validity : out std_logic_vector(1 downto 0)
    );
end dual_priority_encoder;

architecture arch of dual_priority_encoder is
    signal first_signal : std_logic_vector(output_width - 1 downto 0);
    signal second_signal : std_logic_vector(output_width - 1 downto 0);
    signal validity_signal : std_logic_vector(1 downto 0);
begin
    top_proc : process(clk, reset) is
    begin
        if reset = '1' then
            first_signal <= (others => '0');
            second_signal <= (others => '0');
            validity_signal <= (others => '0');
        elsif rising_edge(clk) then
            first_signal <= (others => '0');
            second_signal <= (others => '0');
            validity_signal <= (others => '0');

            outer_loop: for pos in input_width - 1 downto 0 loop
                if input(pos) = '1' then
                    first_signal <= conv_std_logic_vector(pos, output_width);
                    validity_signal <= "01";
                    for pos2 in pos - 1 downto 0 loop
                        if input(pos2) = '1' then
                            second_signal <= conv_std_logic_vector(pos2, output_width);
                            validity_signal <= "11";
                            exit outer_loop;
                        end if;
                    end loop;
                    exit outer_loop;
                end if;
            end loop;
        end if;

        first <= first_signal;
        second <= second_signal;
        validity <= validity_signal;
    end process top_proc;
end arch;

There are two things which I don't like about the code:

  1. I cannot use the constants in the port section of the top entity, because they are defined after the port section of the entity.
  2. I am using conv_std_logic_vector from the ieee.std_logic_arith package. I don't know how to do without it.

Maybe you have a hint for resolving these issues, too?

Regards,

-Markus

EDIT: Code can also be found at **broken link removed**.
 

1. Unfortunately, you can't calculate referred constants in the top entity's generics, because one generic constant can't refer to another. I prefer a package with global defines in this case. It can be placed in the same file in front of the top entity.

2. If you prefer IEEE numeric std library to legacy std_logic_arith, then you should use it's respective conversion functions. It should go like this:
Code:
second_signal <= std_logic_vector(to_unsigned(pos2, output_width));
If "second_signal" is an unsignd numeric entity, I would prefer to use an unsigned type for it, b.t.w.

Frank
 

1. Unfortunately, you can't calculate referred constants in the top entity's generics, because one generic constant can't refer to another. I prefer a package with global defines in this case. It can be placed in the same file in front of the top entity.

even better, if you find yourself putting:

input : std_logic_vector(width-1 downto 0);

in many places, why not declare a subtype.

subtype data_word_t is std_logic_vector(width-1 downto 0);

then on the port:

input : data_word_t;

Saves all the typing!
 

Thank you. I didn't know how easy it is to use my own types; now I know! :smile:
 

even better, if you find yourself putting:

input : std_logic_vector(width-1 downto 0);

in many places, why not declare a subtype.

subtype data_word_t is std_logic_vector(width-1 downto 0);

then on the port:

input : data_word_t;

Saves all the typing!


This is a great tip! But if 'width' is a generic, where do you declare the subtype 'data_word_t' such that it can be used in the port declaration for 'input'?

I was under the impression subtype declarations had to be in a package in order to use them on a port, but packages don't have access to generics.

This has been a big headache for a long time, if you have a work around that would be awesome!
Thanks!
 

To do that, width and the subtype have to exist in a package. But if width applies to many different entities, then having it in a package can help anyway.

VHDL 2008 does actually introduce generics to packages too which may help this.
 

You can have one generic and make the port deceleration use a function of the generic. So std_logic_vector(WIDTH-1 downto 0) and std_logic_vector(work.myUtilPackage.log2(WIDTH)-1 downto 0) can both be in the ports. (normaly you'd 'use' the package so you don't need the "work.myUtilPackage." in there.)

"What happens if the input is only two bits wide? I.e. the output needs to be std_logic instead of std_logic_vector."

You don't want that. Don't switch to a std_logic just because for one instance of an input with the output would be 1-wide. std_logic_vector(0 donwto 0) is a perfectly valid VHDL vector.

"I was under the impression subtype declarations had to be in a package in order to use them on a port, but packages don't have access to generics."

Yeah, VHDL sucks like that. You can't pass in generic sized 2-D arrays, for instance. You can have a generic array of fixed width vectors though. You can take a function of a generic, but you can't declare a type/subtype based on the generic anywhere in the VHDL syntax. What do you think this is? C++ with templates? Ha!
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top