Two questions:
how to get rid of the warning: "Shared variables must be of a protected type." while keeping it as a "shared variable"?
How to fix Attribute "range" requires a constrained array prefix?
First of all, what is a constrained array prefix?
$ vcom.exe -2002 -l test3.vhd
** Warning: test3.vhd(14): (vcom-1236) Shared variables
must be of a protected type.
** Error: test3.vhd(20): (vcom-14402) Attribute "range"
requires a constrained array prefix.
library ieee;
use ieee.std_logic_1164.all;
entity test3 is
end entity;
architecture beh of test3 is
constant dw :integer := 8;
constant depth :integer := 128;
type mem_t is array (integer range<>) of std_logic_vector(dw-1 downto 0);
shared variable ram_block :mem_t(0 to depth-1);
begin
process
variable i:integer;
begin
for i in mem_t'range loop
report integer'image(i);
end loop;
end process;
end architecture;
A protected type in VHDL, is similar to a class in OO programming, where it can have member methods and it can retain state. Since 2002, it is required that shared variables must be of a protected type. By default, most tools only throw a warning to maintain backwards compatibility unless you turn on strict rule checking
So you have two options to remove the warning
revert to VHDL 1993 standard.
Create a protected type.
Your example shows no need for a shared variable. It could be made into a normal (non shared) variable inside the process.
Question 2, I found... But Question 1, I'm still not sure about..
architecture beh of test3 is
constant dw :integer := 8;
constant depth :integer := 128;
type mem_t is array (integer range<>) of std_logic_vector(dw-1 downto 0);
shared variable ram_block :mem_t(0 to depth-1);
begin
process
variable i:integer;
begin
report "left:" & integer'image( ram_block'left);
report "right:" & integer'image( ram_block'right);
for i in ram_block'range loop
report integer'image(i);
end loop;
wait;
end process;
end architecture;
Related
While trying to figure out the specifics of the shift_right function from the numeric_std package I noticed that the count argument is of the subtype NATURAL:
function shift_right(ARG: UNSIGNED; COUNT: NATURAL) return UNSIGNED is
begin
if (ARG'length<1) then return NAU; end if;
return UNSIGNED(XSRL(STD_LOGIC_VECTOR(ARG),COUNT));
end;
However when calling the function I can also provide an INTEGER which in contrast to NATURAL can hold a negative number.
Example of calling code that succesfully compiles:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ExampleCode is
port
(
clk : in std_logic;
input : in signed(15 downto 0);
shift : in signed(3 downto 0);
output : out signed(15 downto 0)
);
end entity;
architecture rtl of ExampleCode is
begin
ProcessExample : process(clk)
begin
if (rising_edge(clk)) then
output <= shift_right(input, to_integer(shift));
end if;
end process;
end rtl;
The numeric_std package shows that if you use to_integer with a signed argument that it returns an integer:
function TO_INTEGER ( ARG: SIGNED) return INTEGER;
My questions are;
Does VHDL always allow parents of subtypes to be provided as arguments to functions?
When it does allow a parent type, how does it resolve the imposed constraints of the subtype?
The other answer is very detailed, but I think goes down a bit of a rabbit hole, when your specific questions can be answered more succinctly. I have answered from a perspecitve of what will practically happen in a real tool that you might use, as opposed to trying to re-interpret the language standard.
An important feature of a subtype is that there is automatic 'conversion'+ to and from the parent type. The example below clearly shows this with an enumerated type. The same automatic conversion would be invoked when passing a parent-type parameter to a function that expects the sub-type.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity e is
end;
architecture a of e is
type r is (A, B, C, D);
subtype rs is r range A to C;
signal x1 : r := B;
signal x2 : r := D;
signal xs : rs;
begin
process
begin
xs <= x1; -- Fine.
wait for 1 ns;
xs <= x2; -- Run-time error, "Value 3 is out of range 0 to 2".
wait;
end process;
end;
Does VHDL always allow parents of subtypes to be provided as arguments to functions?
From the above, yes, it does, but in many tools, you will get an error if the automatic type conversion cannot succeed, as it obviously cannot in the second assignment in the example. Note that if x2 was a constant, a tool could work out that the conversion is not going to be possible, and thrown up a compile-time error then instead.
The same applies with natural and integer; since natural is defined as subtype natural is integer range 0 to integer'high, natural in a sense is an integer, so automatic 'conversion' is simple and reasonable as long as the integer is not outside the natural's range.
When it does allow a parent type, how does it resolve the imposed constraints of the subtype?
Whether standardised or not, a particular tool might implement this in a variety of ways, so you might see different behavior for out-of-range parent-typed values with different tools.
For example, when I tried with ModelSim, it appears that its conversion from integer to natural simply copies the value, meaning that shift_right will surprisingly work with a negative value in that tool, if the shift amount integer is not a constant (at least for version 10.7e).
Obviously it is not sensible to rely on a particular behavior, but regardless of behavior, using a sub type can offer you more protection than just using base types throughout a design.
+ It's not really conversion in VHDL, but if you've used pretty much any other language, this is how you will tend to refer to it.
I have the following code:
library IEEE;
use IEEE.std_logic_1164.all;
entity static_test is
end entity;
architecture sim of static_test is
type rec_t is record
sl : std_logic;
slv : std_logic_vector(6 downto 0);
end record;
type rec_ptr_t is access rec_t;
begin
process
variable ptr : rec_ptr_t;
begin
ptr := new rec_t;
(ptr.sl, ptr.slv) := std_logic_vector'(x"00");
wait;
end process;
end architecture sim;
And I get the following errors from ActiveHDL:
Error: COMP96_0309: static_test.vhd : (28, 6): Expression in element association of the aggregate must be a locally static name that denotes a variable.
Error: COMP96_0309: static_test.vhd : (28, 14): Expression in element association of the aggregate must be a locally static name that denotes a variable.
I cannot find the LRM section that specifies an aggregate assignment needs to be locally static, and I also dont understand why ptr.sl or ptr.slv is not considered locally static. The lengths are known in the type. Is it just that an access type cannot ever be considered locally static (it kind of makes sense to me).
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.
I'm trying to compile my subprogram pack and I get this error:
** Error: C:/Users/kmgrytte/Downloads/subprog_pck.vhd(16): (vcom-1295) Function "parity" has already been defined in this region.
** =====> Prior declaration of "parity" is at C:/Users/kmgrytte/Downloads/subprog_pck.vhd(12).
** Error: C:/Users/kmgrytte/Downloads/subprog_pck.vhd(20): VHDL Compiler exiting
Oveloading like this worked in my main program and I can't find any good examples of overloading in subprograms online.
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
package subprog_pck is
procedure parity;
procedure parity(
in1 : in std_logic_vector(15 downto 0);
in2 : in std_logic_vector(15 downto 0);
par : out std_logic);
function parity return std_logic;
function parity(
indata : in std_logic_vector(15 downto 0)) return std_logic;
impure function parity return std_logic;
impure function parity(
indata : in unsigned(15 downto 0)) return std_logic;
end package subprog_pck;
package body subprog_pck is
procedure parity(
in1 : in std_logic_vector(15 downto 0);
in2 : in std_logic_vector(15 downto 0);
par : out std_logic) is
begin
variable parity1, parity2 : std_logic:=0;
if (rst_n = '0') then
parity1 := '0';
parity2 := '0';
par <= '0';
elsif rising_edge(mclk) then
parity1 := '0';
for i in in1'range loop
if in1(i) = '1' then
parity1 := not parity1;
end if;
end loop;
parity2 := '0';
for j in in2'range loop
parity2 := parity2 xor in2(j);
end loop;
par <= parity1 xor parity2;
end if;
end parity;
function parity(indata : in std_logic_vector(15 downto 0)) return std_logic is
variable parity_var : std_logic := '0';
begin
for i in indata'range loop
if (indata(i) = '1') then
parity_var := not parity_var;
end if;
end loop;
return parity_var;
end function parity;
function parity(indata : in unsigned(15 downto 0))
return std_logic is
variable parity_var : std_logic := '0';
begin
for j in indata'range loop
parity_var := parity_var xor indata(j);
end loop;
return parity_var;
end function parity;
end package body subprog_pck;
Function overloading only occurs when you have the same function name with a different parameter list. Using impure does not overload another function. So you have two version of parity that takes no inputs and outputs a std_logic. Hence the compile error.
You also didn't provide a this version of parity in the package body.
There are additional errors in your package which is missing a library clause (library ieee;) in the context clause. The procedure parity has a variable declaration after begin, your initial values for parity1 and parity2 are 0 (a numeric literal), there's no declaration for rst_n or mclk, par in par <= ... is not a signal, there's no body for procedure parity or function parity with no parameters.
IEEE Std 1076-2008
12.3 Visibility
Two declarations that occur immediately within the same declarative region, other than the declarative region of a block implied by a component instantiation or the declarative region of a generic-mapped package or subprogram equivalent to a package instance or a subprogram instance, shall not be homographs, unless exactly one of them is the implicit declaration of a predefined operation or is an implicit alias of such an implicit declaration.
(There's no implicit declaration here and no predefined operation, emphasis added.)
Also in 12.3
... Each of two declarations is said to be a homograph of the other if and only if both declarations have the same designator, and they denote different named entities, and either overloading is allowed for at most one of the two, or overloading is allowed for both declarations and they have the same parameter and result type profile (see 4.5.1).
4.5 Subprogram overloading
4.5.1
Two formal parameter lists are said to have the same parameter type profile if and only if they have the same number of parameters, and if at each parameter position the corresponding parameters have the same base type. Two subprograms are said to have the same parameter and result type profile if and only if both have the same parameter type profile, and if either both are functions with the same result base type or neither of the two is a function.
You have more than one of these errors. vcom quit after the first one. The order in which errors are found are left to vagaries of the VHDL tool implementation applying semantic rules (other tools might find other errors first, explaining how the errors in the first paragraph above were found).
Modelsim has a verror tool providing more explanation:
vcom Message # 1295:
Two declarations that occur immediately within the same declarative
region must not be homographs, unless exactly one of them is the
declaration of a predefined operation.
Each of two declarations is said to be a homograph of the other if both
declarations have the same identifier, operator symbol, or character
literal, and if overloading is allowed for at most one of the two.
If overloading is allowed for both declarations, then each of the two is
a homograph of the other if they have the same identifier, operator
symbol, or character literal, as well as the same parameter and result
type profile (see 3.1.1). Overloading is defined only for subprograms
(including those those whose designator is an operator symbol) and
enumeration literals (including character literals).
[DOC: IEEE Std 1076-1993 VHDL LRM - 10.3 Visibility]
(These references are from the -1993 revision of the standard.)
I have following simple testcase :
library ieee;
use ieee.std_logic_1164.all;
entity top is
end top;
architecture top of top is
component foo
port (A : std_logic_vector(1 downto 0));
end component;
begin
inst : foo port map (A(1) => '0', A(0) => '0');
end top;
------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity foo is
port (A : std_logic_vector(1 downto 0));
end foo;
architecture foo of foo is
begin
end foo;
When running modelsim on this, it runs fine. But, when I run modelsim with option '-87', it gives me error that Error: top.vhd(13): (vcom-1451) Actual (enumeration literal '0') for formal "A" is not signal name. I am not getting this. Is this some illegal RTL in VHDL'87?
If this is not supported in VHDL'87, then what would be right way to connect a constant to instance pin.
Looking in Modelsim's Verror messages:
vcom Message # 1451: The actual designator is not a static signal
name, it is an expression. In a VHDL 1987 port map, the actual
designator in an association element must be either a static signal
name or a conversion function call whose only argument is a static
signal name. In a subprogram association list in any VHDL language
version, the actual associated with a class SIGNAL subprogram
parameter must be a static signal name.
Later versions of VHDL allow
flexibility in the actual in a port map.
Try using the -93, -2002, or -2008 switch to vcom.
[DOC: IEEE Std 1076-1987 VHDL LRM - 2.1.1.2 Signal parameters,
4.3.3.2 Association Lists]
[DOC: IEEE Std 1076-1993 VHDL LRM - 2.1.1.2 Signal parameters]
So, yes there's a difference in what is valid for an an actual in a port association. The -1993 'liberalization' would also be applicable on later versions (-2002, -2008).
The actual needs to be named and not simply an expression. Inputs with default values can be left open.