Using VHDL generic values in other generics - vhdl

I want to be able to specify a number of channels as a generic and use this to specify the range of an array containing further parameters. When compiling, my Aldec compile tell me that 'num_chan' cannot be referenced until the interface list is complete.
Does anyone know a way to achieve this?
ENTITY deframer IS
generic (
num_chan : integer := 2;
ch_low : int_arr(num_chan-1 downto 0) := ( 1, 189);
ch_hi : int_arr(num_chan-1 downto 0) := (127, 189));

In VHDL-2002 (and earlier), a formal generic declared within a given generic
list can't be used to declared other generics in that list, which is the
reason for the error you see.
In VHDL-2008 that is possible, so if the required tools support VHDL-2008 and
that feature ("Referencing generics in generic lists"), then you can indicate
to the tools that VHDL-2008 is used.
A solution for VHDL-2002, is to make the ch_low and ch_hi arrays large
enough to accommodate any value of num_chan, and then fill the unused with a
dummy value, like (assuming num_chan is at most 10, using -1 as dummy value):
generic(
num_chan : integer := 2;
ch_low : int_arr_t(1 to 10) := ( 1, 189, others => -1);
ch_hi : int_arr_t(1 to 10) := (127, 189, others => -1));

Related

Can you make an array of types in VHDL?

Vivado Simulation cannot support unconstrained types which have a signed component to them.
i.e.
type A is array (natural range <>) of signed;
I have been using this in a design where type A is used in port declarations as I wish to have a parallel design which I control through a generic as well as the current stage word length e.g.
port (
inputdata : A(0 to number_of_parallel_generic-1)(stage_wordlength_generic-1 downto 0)
);
As I use the type A with many variations of the generics controling them e.g. 4 wide arrays with 16 wordlengths and other variations (often controled by a for generate loop)
for i in 0 to length_of_generate_statement-1 generate
signal example_signal : A(0 to 3)(stage_wordlength_generic + i - 1 downto 0);
begin
<functional code>
end generate;
This sort of code would allow me to gain bit growth from sequential sections of my archetecture - e.g. from an addition.
Now... getting to the question at hand.
One way I could get round this rather than initiating a signal with a forever changing generate statement could actually be in the creation of an "array of types".
Lend me your eyes this is written in a not quite vhdl way but hopefully you can see what Im trying to do.
type my_arr_of_types is array(0 to length_of_array-1) of type;
for i in 0 to length_of_array-1 generate
my_arr_of_types(i) <= <type declaration with some dependance on i>;
end generate;
Hopefully you can see what I am trying to do.
This would allow you to then call an element of the my_arr_of_types which itself is a type to then assign to a signal/variable.
i.e.
signal my_sig : my_arr_of_types(n);
*Where n is any valid index of the array.
Obviously this is not allowed in VHDL or any simulation tool. But can anyone see a potential solution to my problem?
Remember I use most of these types on port statements so any solution has to fit within the limitations of the port declarations.
Using two dimensional arrays as a solution:
Package
library ieee;
use ieee.numeric_std.all;
package utilities is
type T_SLM is array(natural range <>, natural range <>) of std_logic;
end package;
Entity
Now you can use this type in a port declaration together with two generic parameters. As sizes are now known in the architecture, you can create your used defined type of signed values and you can use either generate statements or a function to convert from the T_SLM to myArray type.
library ieee;
use ieee.numeric_std.all;
library myLib;
use myLib.utilities.all;
entity foo is
generic (
number_of_parallel : natural;
stage_wordlength : natural
);
port (
Input : T_SLM(0 to number_of_parallel - 1, stage_wordlength - 1 downto 0)
);
end entity;
architecture a of foo is
type myArray is array (natural range <>) of signed(Input'range(2));
function convert(matrix : T_SLM) return myArray is
variable result : myArray(matrix'range(1));
begin
for i in matrix'range(1) loop
for k in matrix'range(2) loop
result(i)(j) := matrix(i, j);
end loop;
end loop;
return result;
end function;
signal InputData1 : myArray(Input'range(1));
signal InputData2 : myArray(Input'range(1));
begin
genInput: for i in Input'range(1) generate
genInput: for j in Input'range(2) generate
InputData1(i)(j) <= Input(i, j);
end generate;
end generate;
InputData2 <= convert(Input);
end architecture;
Many helper functions like this have been implemented in the PoC Library in package PoC.vectors.

How to constrain VHDL-2008 integer_vector?

VHDL-2008 defines
type integer_vector is array (natural range <>) of integer
and it can be used to create arrays of unconstrained integers just fine:
signal sUnconsrainedIntA : integer_vector(0 to 1) := (others => 0);
However, how to declare array of constrained integers, e.g:
-- does not work:
-- signal sConstrainedTestIntA : integer_vector(0 to 1) range 0 to 3 := (others => 0);
-- ** Error: filetest.vhd(65): Range constraints cannot be applied to array types.
-- ** Error: filetest.vhd(65): Range expression is type Integer; expecting type std.STANDARD.INTEGER_VECTOR
-- What you can do is:
type my_int_array is array (natural range <>) of integer range 0 to 3;
signal sConstrainedIntA : my_int_array(0 to 1) := (others => 0);
Is there a way to constrain the integers in the array without the custom type?
VHDL 2008 supports package generic parameters. You could try something like:
package foo_pkg is
generic(l, h: integer);
subtype my_integer is integer range l to h;
type my_integer_vector is array(natural range <>) of my_integer;
end package foo_pkg;
package foo_pkg_m17_p39 is new work.foo_pkg
generic map(l => -17, h => 39);
package foo_pkg_p57_p134 is new work.foo_pkg
generic map(l => 57, h => 134);
entity foo is
port(iv1: work.foo_pkg_m17_p39.my_integer_vector(0 to 7);
iv2: work.foo_pkg_p57_p134.my_integer_vector(0 to 7)
);
end entity foo;
Not very user friendly because you need one package instantiation declaration per integer constraint. But it is what I found that resembles most what you ask for...
Even if it looks more complicated than what you expected, it still allows you to factorize your custom code for all variants of my_integer_vector.

VHDL: How to declare a variable width generic [duplicate]

This question already has answers here:
How to use generic parameters that depend on other generic parameters for entities?
(2 answers)
Closed 6 years ago.
I want to create a VHDL entity with a one generic that changes the width of another generic.
entity lfsr_n is
generic (
WIDTH : integer := 32; -- counter width
POLYNOMIAL : std_logic_vector (WIDTH-1 downto 0) := "1000_0000_0000_0000_0000_0000_0110_0010"
);
Unfortunately, it seems I can't reference an earlier defined generic later in the generic list. Active-HDL gives the following errors:
Error: COMP96_0300: modules/m3_test_load/lfsr_n.vhd : (26, 45): Cannot reference "WIDTH" until the interface list is complete.
Error: COMP96_0077: modules/m3_test_load/lfsr_n.vhd : (26, 66): Undefined type of expression. Expected type 'STD_LOGIC_VECTOR'.
One workaround would be to make POLYNOMIAL a port. But it properly should be a generic since since the value is constant at elaboration time. I know that if I apply a constant to the port, it will synthesize the way I want and optimize the constants values into the module, but I'd like to find someway to make it a generic. Any suggestions how to do this?
If you want the POLYNOMIAL parameter to remain a generic you can specify it as an unconstrained array. You can also dispense with the WIDTH parameter by replacing all references by POLYNOMIAL'range, POLYNOMIAL'length-1 downto 0, or POLYNOMIAL'length as needed.
entity lfsr_n is
generic (
POLYNOMIAL : std_logic_vector := X"FFAA55BB"
);
port (
-- Vector with copied range (defaults to ascending from 0)
state : out std_logic_vector(POLYNOMIAL'range);
-- Vector with forced descending range
state2 : out std_logic_vector(POLYNOMIAL'length-1 downto 0)
);
end entity;
Unconstrained arrays are a powerful feature that help simplify code by implicitly controlling widths rather than needing a dedicated generic parameter. When used effectively they reduce the number of hard-coded array sizes in your source resulting in naturally resizable logic. You can freely change the POLYNOMIAL generic to another value with a different length and the rest of your logic should adapt without any additional effort.
There's an entity declarative part following any generic and any port declaration:
library ieee;
use ieee.std_logic_1164.all;
entity lfsr_n is
generic (
WIDTH: integer := 32 -- counter width
);
port (
foo: integer
);
constant POLYNOMIAL: std_logic_vector (WIDTH-1 downto 0)
:= B"1000_0000_0000_0000_0000_0000_0110_0010";
end entity;
architecture foo of lfsr_n is
begin
end architecture;
This analyzes and elaborates showing the generic is properly used.
You could also note that the literal you assign to the std_logic_vector doesn't adapt to changing WIDTH. I would have thought these '1's stand for tap off locations and you'd expect these could change from one LFSR length to another.
You could convey the 'WIDTH' in the polynomial constant:
library ieee;
use ieee.std_logic_1164.all;
entity lfsr_n is
generic (
-- WIDTH: integer := 32; -- counter width
POLYNOMIAL: std_logic_vector :=
B"1000_0000_0000_0000_0000_0000_0110_0010"
);
port (
foo: integer
);
-- constant POLYNOMIAL: std_logic_vector (WIDTH-1 downto 0)
-- := B"1000_0000_0000_0000_0000_0000_0110_0010";
end entity;
architecture foo of lfsr_n is
signal shft_register: std_logic_vector (0 to POLYNOMIAL'LENGTH-1);
begin
end architecture;
Or:
architecture foo of lfsr_n is
-- signal shft_register: std_logic_vector (0 to POLYNOMIAL'LENGTH-1);
-- or
signal shift_register: std_logic_vector(POLYNOMIAL'RANGE);

No function declarations for operator + error in VHDL

In this piece of code I get this error for the line with +
function func (bv1 : in bit_vector; bv2 : in integer) return bit_vector is
variable temp : natural := 2**bv2;
variable result : bit_vector(1 to 32);
begin
report "asd" & natural'image(temp);
result <= bv1 + temp; // this line causes the error
return result;
end func;
The error is :
No function declarations for operator +
How can I solve this? I also get a similar error for "=" as well.
Don't use bit_vectors (or std_logic_vectors, really) for anything you want to do arithmetic on.
Use the ieee.numeric_std library and then declare your signals (or whatever) to be of type signed ot unsigned depending on what type of vector you want. (Or of course, you can just use integers and the subtypes of that)
It's because you try to add a natural to a bit_vector which does not work because they are of different types. So you'll have to use a converter, e.g. as shown here within one of the functions. The other method is to stick to all the same types, but that isn't always possible.
Some initial problems with the code are that VHDL comments markup is --, not
//, and assign to result variable must use :=, since <= is for assign
to signal.
Then, the reason for the error:
No function declarations for operator +
is that VHDL is a strong typed language, so it is not possible just to add a
natural type and a bit_vector type, as attempted in result <= bv1 + temp.
Instead you need to use the package numeric_bit_unsigned, and for example
convert temp to bit_vector using function to_bitvector before adding.
Resulting code can then be:
library ieee;
use ieee.numeric_bit_unsigned.all;
...
function func (bv1 : in bit_vector; bv2 : in integer) return bit_vector is
variable temp : natural := 2**bv2;
variable result : bit_vector(1 to 32);
begin
report "asd" & natural'image(temp);
result := bv1 + to_bitvector(temp, result'length); -- this line causes the error
return result;
end func;
You should check that the length is enough to handle the required values.
However, instead of using bit_vector type, you may consider the
std_logic_vector (depending on the design), since the std_logic_vector has
additional values that may reveal design problem in simulation.

How to use generic parameters that depend on other generic parameters for entities?

I am trying to convert some Verilog code that produces a slower clock from a faster clock for a UART module. The original verilog code is based on the module over at fpga4fun.com, and this is my attempt to translate it for my VHDL-based design.
entity baud_generator is
generic(
f_clk : integer := 50000000; -- default: 50 MHz
baud : integer := 115200; -- default: 115,200 baud
accum_width : integer := 16;
accum_inc : integer := (baud sll accum_width) / f_clk
);
port(
clock : in std_logic;
reset_n : in std_logic;
enable : in std_logic;
baud_clock : out std_logic
);
end entity baud_generator;
However, my compiler, Aldec-HDL, doesn't like the following line:
accum_inc : natural := (baud sll accum_width) / f_clk
Here is the exact error message:
# Error: COMP96_0300: baud_generator.vhd : (20, 52): Cannot reference "f_clk" until the interface list is complete.
# Error: COMP96_0300: baud_generator.vhd : (20, 28): Cannot reference "baud" until the interface list is complete.
# Error: COMP96_0071: baud_generator.vhd : (20, 28): Operator "sll" is not defined for such operands.
# Error: COMP96_0104: baud_generator.vhd : (20, 27): Undefined type of expression.
# Error: COMP96_0077: baud_generator.vhd : (20, 27): Assignment target incompatible with right side. Expected type 'INTEGER'.
In verilog, I have something like this:
module baud_generator(
input clock,
input reset_n,
input enable,
output baud_clock
);
parameter f_clock = 50000000;
parameter baud = 115200;
parameter accum_width = 16;
parameter accum_inc = (baud << accum_width) / f_clock;
//...
endmodule
What is it that I need to modify in that line to make the compiler happy? Is it possible to use generics chained together like that?
This basically says you cannot do computations with the generic values to caluclate (default values for) other generics.
Just use accum_inc as a constant, not as a generic.
Also, the SLL (shift logic left) operator is meant for bit patterns (unsigned and signed datatypes in the ieee.numeric_std and ieee.numeric_bit packages), not for integers. You can do the same by multiplying by a power of two.
It looks to me like accum_inc is a constant, not a parameter (as it's calculated from the generics, so there's no reason to override it)
So it doesn't want to be in the generic part - simply move it to the architecture and make it a constant (and as Philippe noted, do your shifting with multiplies):
constant accum_inc : integer := (baud * (2**accum_width)) / f_clk;
You may find that you overflow what integers can manage, depending on the values of the generics, so you might find you want to use unsigned vectors in the generics and/or calculation.

Resources