VHDL-2008 Convert Array Width - vhdl

Let's say I have the following:
type slv1_array is array (natural range <>) of std_logic_vector(0 downto 0);
type slv2_array is array (natural range <>) of std_logic_vector(1 downto 0);
type slv3_array is array (natural range <>) of std_logic_vector(2 downto 0);
type slv4_array is array (natural range <>) of std_logic_vector(3 downto 0);
type slv5_array is array (natural range <>) of std_logic_vector(4 downto 0);
type slv6_array is array (natural range <>) of std_logic_vector(5 downto 0);
type slv7_array is array (natural range <>) of std_logic_vector(6 downto 0);
type slv8_array is array (natural range <>) of std_logic_vector(7 downto 0);
type slv9_array is array (natural range <>) of std_logic_vector(8 downto 0);
...
Is there a general way in VHDL-2008 to specify the conversion between any of these types without defining conversion functions for every possible permutation?

No, there is not. Each array you have created is a specific type, and hence the lengths all mismatch, so a "general way" would not be appropriate - how would you assign a 4 bit vector to a 5 bit vector, for example?
But VHDL-2008 does support unconstrained arrays. Having to have so many types of arrays with different length elements is frustrating. So instead, why no just declare:
type slv_array_t is array(natural range <>) of std_logic_vector; -- element unconstrained, allowed in 2008
then when you declare an object, you can constrain both dimensions:
signal slv8_8 : slv_array_t(0 to 7)(7 downto 0);
signal slv16_16 : slv_array_t(15 downto 0)(15 downto 0);
now slv8_8 and slv16_16 have the same base type, which can be useful in testbenches, with things like access types.
type slv_array_ptr_t is access slv_array_t;
variable v1 : slv_array_ptr_t;
...
v1 := new slv_array_t'(slv8_8);
v1 := new slv_array_t'(slv16_16);
doing this in 1993 would not be possible, access types for each of your types would be required, and hence separate variable objects to store them. VHDL 2008 allows much easier transfer.

Related

How to constrain dimension in uncosntrained array when 1st is already constrained?

With VHDL 2008, you are allowed to define unconstrained types/subtypes. For example:
slv_array_t is array(natural range <>) of std_logic_vector;
then you can create subtypes where one or more dimensions is left open to be constrained later.
subtype slv32_array_t is slv_array_t(open)(31 downto 0);
signal some_object : slv32_array_t(7 downto 0);
This is fine when the open dimensions are the first ones. But how can I constrain a subtype if the unconstrained dimension is not the first one? The following gives the error inn ActiveHDL that the dimension is already constrained.
Index constraint cannot be applied to constrained type.
subtype slv_array8_t is slv_array_t(7 downto 0)(open); -- legal
signal some_object : slv_array8_t(31 downto 0);
The following also compains with the same error:
signal some_object : slv_array8_t(7 downto 0)(31 downto 0);
So, is there actually a way this type can be constrained in an object with VHDL 2008? Did it even make it into VHDL 2019?
You just need to use (open) to "jump over" the constrained dimension, just like you did with the subtype:
signal some_object : slv_array8_t(open)(31 downto 0);
library IEEE;
use IEEE.std_logic_1164.all;
entity E is
end entity E;
architecture A of E is
type slv_array_t is array(natural range <>) of std_logic_vector;
subtype slv32_array_t is slv_array_t(open)(31 downto 0);
signal some_object : slv32_array_t(7 downto 0);
subtype slv_array8_t is slv_array_t(7 downto 0)(open); -- legal
signal some_object2 : slv_array8_t(open)(31 downto 0);
begin
end architecture A;
https://www.edaplayground.com/x/reNU

in VHDL, is it possible to create an array of std_logic_vector without using a type?

In SystemVerilog I can create a multidimensional array as follows:
reg [31:0] mem[0:127];
However, in VHDL all of the examples for create a similar multidimensional arrays online in the VHDL book show that I must first create a type before creating the array. Example:
type mem_t is array(0 to 127) of std_logic_vector(31 downto 0);
signal mem :mem_t;
Is it possible to do this all in one step in VHDL like in verilog without first creating a type for the array? Example:
signal mem :array(0 to 127) of std_logic_vector(31 downto 0);
--syntax error:GHDL: Type mark expected in a subtype indication
--syntax error:vsim: near "array": (vcom-1576) expecting STRING or IDENTIFIER or << or '('
The reason why i'm asking is because i'm trying to avoid the use of a package to declare an array type, when connecting IO with an array that is connected between to modules in VHDL.
What you created is an array of an array - which is in general what you want. What #Matthew Taylor created is a multidimensional array.
WIth VHDL-2008 the elements of a composite can be unconstrained, and hence, you can create:
type std_logic_aoa is array (natural range <>) of std_logic_vector;
Realistic speaking this should be in a standard library - it is just not there currently.
And then you can use it by doing:
signal mem : std_logic_aoa (0 to 127)( 31 downto 0);
The reason you want an array of an array here is it allows you to do things like:
signal Data : std_logic_vector(31 downto 0) ;
. . .
Data <= mem(15) ;
No. It isn't.
It is possible to create genuinely multi-dimensional arrays in VHDL, but you still need to create a new type. That is the VHDL way. So, you'll still need your package.
Here's a multi-dimensional constrained array:
type c_mem_t is array (0 to 127, 31 downto 0) of std_logic;
and here's a multi-dimensional unconstrained array:
type mem_t is array (natural range <>, natural range <>) of std_logic;
And you use them like this:
signal mem : c_mem_t;
signal mem : mem_t(0 to 127, 31 downto 0);
In VHDL-2002 either both dimensions must be constrained or both must be unconstrained. In VHDL-2008, you can have one constrained and one not:
type mem_t_2008 is array (natural range <>, 31 downto 0) of std_logic;

VHDL logic vector to record assignment

Suppose I have defined a record with fields of std_ulogic_vector to represent a larger std_ulogic_vector. It's straightforward to convert this record to the large vector using a concatenation (without knowledge of the size for each field).
How do I do the reverse, e.g. convert the large std_ulogic_vector back to the record ?
Example :
architecture RTL of record_conversion is
type data_t is record
top : std_ulogic_vector(4 downto 0);
bottom : std_ulogic_vector(2 downto 0);
end record data_t;
signal record_s : data_t;
signal vector_s : std_ulogic_vector(7 downto 0);
begin
-- vector to record works
--vector_s <= record_s.top & record_s.bottom;
-- record to vector does not work
(record_s.top, record_s.bottom) <= vector_s;
-- tedious solution with knowledge of the field size
record_s.top <= vector_s(7 downto 3);
record_s.bottom <= vector_s(2 downto 0);
end architecture;
It is usually a good idea to wrap such conversion in functions, and with a subtype for resulting vector, like:
...
constant LEN : integer := 8; -- Number of bits in data_t
type data_t is record
top : std_ulogic_vector(4 downto 0);
bottom : std_ulogic_vector(2 downto 0);
end record data_t;
subtype vector_t is std_ulogic_vector(LEN - 1 downto 0);
function data_to_vector(data : data_t) return std_ulogic_vector is
variable res_v : vector_t;
begin
res_v := data.top & data.bottom;
return res_v;
end function;
function vector_to_data(vector : vector_t) return data_t is
variable res_v : data_t;
begin
res_v.top := vector(LEN - 1 downto LEN - res_v.top'length);
res_v.bottom := vector(res_v.bottom'length - 1 downto 0);
return res_v;
end function;
signal record_s : data_t;
signal vector_s : vector_t;
begin
record_s <= vector_to_data(vector_s);
vector_s <= data_to_vector(record_s);
...
Maybe another constant should be added to define the split between top and bottom.
There are a couple of other methods besides using subprogram calls to assign elements of one type to elements of another type.
You can use a qualified expression:
record_s <= data_t'(vector_s(7 downto 3), vector_s (2 downto 0));
Where the aggregate comprised of two slices of vector_s with an explicit type matching the record. See IEEE Std 1076-2008 9.3.6 Qualified expressions.
During simulation new values for signals are validated. See 14.7.3.4 Signal update:
b) If S is a composite signal (including a slice of an array), the effective value of S is implicitly converted to the subtype of S. The subtype conversion checks that for each element of S there is a matching element in the effective value and vice versa. An error occurs if this check fails. The result of this subtype conversion is then assigned to the variable representing the current value of S.
Besides having a matching element (subelement,...) subtype conversion changes the index ranges to match the target.
You can specify the slice index ranges with subtype index ranges:
library ieee;
use ieee.std_logic_1164.all;
entity record_conversion is
end entity;
architecture subtypes of record_conversion is
type data_t is record
top : std_ulogic_vector(4 downto 0);
bottom : std_ulogic_vector(2 downto 0);
end record data_t;
signal record_s : data_t;
signal vector_s : std_ulogic_vector(7 downto 0);
subtype t is std_logic_vector (
vector_s'LEFT downto vector_s'LEFT - record_s.top'length + 1
);
subtype b is std_logic_vector (
vector_s'LEFT - record_s.top'length downto 0
);
begin
record_s <= data_t'(vector_s(t'range), vector_s(b'range));
end architecture;
Here the subtypes index range slices of the right hand side expression elements.
You can describe the slices with aliases:
architecture aliases of record_conversion is
type data_t is record
top: std_ulogic_vector(4 downto 0);
bottom: std_ulogic_vector(2 downto 0);
end record data_t;
signal record_s: data_t;
signal vector_s: std_ulogic_vector(7 downto 0);
alias vector_s_top: std_ulogic_vector(record_s.top'range) is
vector_s(7 downto 3);
alias vector_s_bottom: std_ulogic_vector(record_s.bottom'range) is
vector_s (2 downto 0);
begin
record_s <= data_t'(vector_s_top, vector_s_bottom);
end architecture;
Here the two aliases describe fields of vector_s. If you were guaranteed to always assign the record composite object you could actually do away with records and simply use aliases. The closest VHDL comes to unions.
The above examples analyze, elaborate and simulate without error, demonstrating there are no slice boundary issues.
Qualified expressions, subtype declarations and aliases incur no additional simulation overhead while subprogram calls do.

Get position or range of alias

Suppose I have an alias for a a single bit or number of bits in a std_logic_vector declared such as this:
signal CR : std_logic_vector(7 downto 0);
alias CR_ARM : std_logic is CR(0);
alias CR_PS : std_logic_vector(3 downto 0) is CR(7 downto 4);
How can I access the range or position of the alias such as:
singal tmp : std_logic_vector(7 downto 0); -- output bus vector
tmp(CR_ARM'range) <= CR_ARM; -- does not compile
Range is only defined for array types. Even when VHDL-2017 will add ranges for scalar types, it won't solve your problem, because you want to know for which bit the alias was created.
Aliases are transparent in VHDL. There is no mechanism to reflect about aliases.
You could use this workaround, which doesn't look very nice:
signal CR : std_logic_vector(7 downto 0);
alias CR_ARM : std_logic_vector is CR(0 downto 0);
signal tmp : std_logic_vector(7 downto 0); -- output bus vector
-- now a slice name works
tmp(CR_ARM'range) <= CR_ARM;
Your second example won't work as expected. You should declare the alias with the same range constraints otherwise you will assign other bits when you use CR_PS'range.

How to multiply by 2 a 32 bit signed std_logic_vector in VHDL

We have a type which is an array of 32 bit "std_logic_vector" of size 3, which is defined in the following way:
subtype scalar is std_logic_vector(31 downto 0);
type vector_nd is array (natural range <>) of scalar;
subtype vector_3d is vector_nd(2 downto 0);
We have a signal of type "vector_3d" which we want to multiply by 2 and put the result in a signal of type "scalar":
signal v_normal_out_sig := vector_3d;
signal mult1_in1_sig := scalar;
--...
mult1_in1_sig <= 2*signed(v_normal_out_sig(0)) when cau_state = st_cycle18;
When we compile it we get the error:
No feasible entries for infix operator "*".
What is the right way to implement what we want? We are using the following libraries:
ieee.std_logic_1164.all
ieee.std_logic_arith.all
ieee.std_logic_unsigned.all
What we did eventually is the fallowing:
mult1_in1_sig <= v_normal_out_sig(0)(31) & v_normal_out_sig(0)(29 downto 0) & '0' when cau_state = st_cycle18;
And test gave the right results for both positive and negative numbers.

Resources