i'm writing a small vhdl module, but i'm quite new to this language. The length of the output vector of my entity is variable, depending on the msb of my polynom. For example if i have a polynom like 100111, len should be 4. So the output vector has 5 bits. One less than the input vector.
For clarification: If the inputvector looks like "000100111", the output vector should also be (4 downto 0). That's why i just can't use 'length.
entity CRC_n_par is
generic(
polynom : std_logic_vector
);
port(
clk : in std_logic;
input : in std_logic;
reset : in std_logic;
output : out std_logic_vector(integer(ceil(log2(real(to_integer(unsigned(polynom))))))-2 downto 0) );
end entity;
architecture Behavioral of CRC_n_par is
constant len : integer := integer(ceil(log2(real(to_integer(unsigned(polynom))))))-2;
Is there any way, to do this more elegant. Here's a similar question, but i cannot use a function in the port declaration. After the port declaration, i use the constant len again. Is there a way to use a c-like macro in vhdl? I'm using vhdl 2008, that's why the conversion is so complicated, because i can only convert between closely related types.
The length is also needed were crc_n_par is instantiated:
library ieee;
use ieee.std_logic_1164.all;
entity crc_n_par is
generic (
len: natural
);
port (
clk: in std_logic;
input: in std_logic;
reset: in std_logic;
output: out std_logic_vector (len - 1 downto 0)
);
end entity;
architecture Behavioral of crc_n_par is
begin
MONITOR:
process
begin
report "crc_n_par output len = " & integer'image(len);
wait;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity some_top_level is
end entity;
architecture foo of some_top_level is
-- For -2002 and earlier, present in -2008:
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
constant polynom: std_logic_vector := "000100111";
constant crc_inst_len : natural :=
integer(ceil(log2(real(to_integer(unsigned(polynom))))))-1;
signal clk: std_logic;
signal input: std_logic;
signal reset: std_logic;
signal output: std_logic_vector (crc_inst_len - 1 downto 0);
begin
MONITOR:
process
begin
report LF & "polynom len = " & integer'image(polynom'length) &
" crc_inst_len = " & integer'image(crc_inst_len) & LF &
" output length = " & integer'image(output'length) &
" polynom = " & to_string(polynom);
wait;
end process;
CRC_INSTANCE:
entity work.crc_n_par
generic map (
len => crc_inst_len
)
port map (
clk => clk,
input => input,
reset => reset,
output => output
);
end architecture;
This moves the length calculation to a higher point in the design hierarchy allowing the actual used for the port output to be declared with the proper length as well.
When analyzed, elaborated and simulated it produces:
ghdl -a some_top_level.vhdl ghdl -e some_top_level ghdl -r some_top_level some_top_level.vhdl:20:9:@0ms:(report note): crc_n_par output len = 5 some_top_level.vhdl:55:9:@0ms:(report note): polynom len = 9 crc_inst_len = 5 output length = 5 polynom = 000100111
You can independently calculate the length two places:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity crc_n_par is
generic (
polynom: std_logic_vector;
len: natural := -- requires -2008 to access polynom
integer(ceil(log2(real(to_integer(unsigned(polynom)))))) - 1
);
port (
clk: in std_logic;
input: in std_logic;
reset: in std_logic;
output: out std_logic_vector (len - 1 downto 0)
);
end entity;
architecture Behavioral of crc_n_par is
begin
MONITOR:
process
begin
report "len = " & integer'image(len);
wait;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity some_top_level is
end entity;
architecture foo of some_top_level is
constant polynom: std_logic_vector := "000100111";
constant crc_inst_len : natural :=
integer(ceil(log2(real(to_integer(unsigned(polynom))))))-1;
signal clk: std_logic;
signal input: std_logic;
signal reset: std_logic;
signal output: std_logic_vector (crc_inst_len - 1 downto 0);
begin
MONITOR:
process
begin
report LF & "polynom len = " & integer'image(polynom'length) &
" crc_inst_len = " & integer'image(crc_inst_len) & LF &
" output length = " & integer'image(output'length) &
" polynom = " & to_string(polynom);
wait;
end process;
CRC_INSTANCE:
entity work.crc_n_par
generic map (
polynom => polynom
-- don't pass len
)
port map (
clk => clk,
input => input,
reset => reset,
output => output
);
end architecture;
But you can see that's unnecessary duplication and requires -2008 to analyze and elaborate:
ghdl -a --std=08 crc_n_par.vhdl ghdl -e --std=08 crc_n_par ghdl -r --std=08 some_top_level some_top_level.vhdl:20:9:@0ms:(report note): crc_n_par output len = 5 some_top_level.vhdl:55:9:@0ms:(report note): polynom len = 9 crc_inst_len = 5 output length = 5 polynom = 000100111
Note the - 1
in calculating polynom
length matches your question title:
VHDL 2008 calculate length of vector without leading zeros
And this is the purpose of using conversion of the array value to an integer and determining it's log2 ceiling and subtracting one.