Subert
Subert

Reputation: 638

Raise a number to a power that varies in VHDL

I have need to write a process that implement this correlation table :

E -> S

0 -> 2

1 -> 4

2 -> 8

3 -> 16

4 -> 32

5 -> 64

and so forth.

You can see clearly that the output can be easily calculated :

S = 1^(E+1)

However I'm not sure if it is possible to do this in VHDL with left shift. What bothers me is that we don't know in advance the size of (E+1) so we don't know how many 0 needs to be added so both sides of the equations have the same size.

Is there a smart way to do this in VHDL (smarter than to do a MUX) ?

Upvotes: 1

Views: 3082

Answers (2)

gsm
gsm

Reputation: 408

There are few different ways to achieve this (for the purpose of synthesis); I'm sure there are more than those listed here. If E is an input generic to your module (which it doesn't sound like it is, otherwise you would know what E+1 is in advance), no "additional" logic is required.

If E is an input to the module, but you have an upper bound on E, you could simply use a ROM as a lookup (This isn't an efficient use of memory, but will work). Alternatively, you could use a function that takes E as an input and returns a vector that represents the result, S (Note that this also requires E being bounded, which bounds the size of the result).

constant MAX_WID : natural := 64;
...

-- You can use unsigned in place of slv, if that is more suitable
function calc_s(e : integer) return std_logic_vector is
    -- MAX_WID is effectively your maximum value of E
    variable ret : std_logic_vector(MAX_WID+1 downto 0) := (others => '0');
begin
    ret(e+1) := '1';
    return ret;
end calc_s;

Upvotes: 1

JHBonarius
JHBonarius

Reputation: 11281

This is possible in many ways. E.g. To start:

use ieee.math_real.all;

constant E : natural := 0; -- any value >= 0
constant S : integer := natural(2 ** real(E+1));

Or

use ieee.numeric_std.all;
....
constant E : natural := 0;
constant S : unsigned((E+1) downto 0):= (
    (E+1) => '1',
    others => '0');

Or

use ieee.math_real.all;
use ieee.numeric_std.all;
....
constant E : natural := 0;
constant S : unsigned((E+1) downto 0) :=
    to_unsigned(integer(2 ** real(E+1)), E+2));

Or

use ieee.numeric_std.all;
....
constant E : natural := 0;
signal S : unsigned((E+1) downto 0);
....
S <= left_shift(to_unsigned(1, (E+2)), E+1);

Etc, etc.

I mean, what would you like to achieve?

Upvotes: 0

Related Questions