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
Related
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.
I have a signal dataIn : std_logic_vector ( 15 downto 0);
I want to give an input less than 16-bits for example dataIn <= x"000a" and those bits occupy the most significant bits and the rest to be zero.
In verilog you can do that very easy but in VHDL you get the error:
"string length does not match that of the anonymous integer subtype defined t... ".
I know that if you use 16x"bit_string" solves the problem but this is only for VHDL-2008 and ghdl doesn't support yet VHDL-2008.
Are there any method for IEEE Std 1076-2002?
For VHDL-87/93/2002 you could use the resize function from the numeric_std package.
library ieee;
use ieee.numeric_std.all;
...
constant FOO : std_logic_vector(2 downto 0) := "010";
signal dataIn : std_logic_vector(15 downto 0) := std_logic_vector(resize(unsigned(FOO), 16));
Note that the resize function is only defined for types signed and unsigned.
If you want the short bit string to be placed into the MSBs you may need to use the 'reverse_order attribute.
Often you will find it easier to define a dedicated function which encapsulates more complicated initializations.
constant FOO : std_logic_vector(2 downto 0) := "010";
function init_dataIn (bar : std_logic_vector; len : integer) return std_logic_vector is
begin
return bar & (len - bar'length - 1 downto 0 => '0');
end function init_dataIn;
signal dataIn : std_logic_vector(15 downto 0) := init_dataIn(FOO, 16);
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.
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.
This has me bugging for quite some time, but is it possible to describe entities in VHDL similar to how templates work in C++ (or to lesser extend generics?). Simply leaving the actual port types to be only decided during synthesize/compilation?
An example would be a multiplexer, say I have a 4 input multiplexer, now I have several bus sizes I use this multiplexer for, -4,6,7,8-. Currently I wrote a different multiplexer for each different bus size; however the output is simply one of the chosen inputs forwarded, and is thus of the same type as the bus.
This seems overly redundant and error prone (choose correct multiplexer at correct times, keep them all in line, update them as I change the bus size). Is there no way to parameterize this?
non generic version below to show the idea.
entity mux_6bit_4input is
port ( input_0 : in std_logic_vector (5 downto 0);
input_1 : in std_logic_vector (5 downto 0);
input_2 : in std_logic_vector (5 downto 0);
input_3 : in std_logic_vector (5 downto 0);
sel : in std_logic_vector (1 downto 0);
output : out std_logic_vector (5 downto 0)
);
end entity mux_6bit_4input;
Maybe I misunderstood the question, but doesn't the common solution using generics solve your problem?
library ieee;
use ieee.std_logic_1164.all;
entity mux_4x1 is
generic (
DATA_WIDTH: integer := 8
);
port (
input_0: in std_logic_vector(DATA_WIDTH-1 downto 0);
input_1: in std_logic_vector(DATA_WIDTH-1 downto 0);
input_2: in std_logic_vector(DATA_WIDTH-1 downto 0);
input_3: in std_logic_vector(DATA_WIDTH-1 downto 0);
sel: in std_logic_vector (1 downto 0);
output: out std_logic_vector(DATA_WIDTH-1 downto 0)
);
end;
architecture behavior of mux_4x1 is
begin
output <=
input_0 when sel = "00" else
input_1 when sel = "01" else
input_2 when sel = "10" else
input_3;
end;
Another solution, if you want to keep things really generic, is to use the cool generic types in VHDL-2008. My simulator doesn't yet support this feature, so here's an example from the excellent book VHDL 2008: Just the New Stuff:
entity generic_mux2 is
generic (type data_type);
port (
sel: in bit;
a, b: in data_type;
z: out data_type
);
end;
architecture rtl of mux2 is
begin
z <= a when sel = '0' else b;
end;
Another option is to use unconstrained arrays:
entity mux_4input is
port (
input_0 : in std_logic_vector ;
input_1 : in std_logic_vector ;
input_2 : in std_logic_vector ;
input_3 : in std_logic_vector ;
sel : in std_logic_vector (1 downto 0);
output : out std_logic_vector
);
end entity mux_4input;
They will inherit their width (and direction) from the signals they are conencted to in the instantiating entity.
It's probably not the right thing to do in this particular case of a mux, rick's answer is what I'd go for, but unconstrained arrays don't get mentioned much, so I thought I'd offer them! In this case, you'd probably also want some asserts to ensure that everything you've wired up is the same width.