Force VHDL to use generic over constant - vhdl

I have some VHDL where a generic is the same name as a constant in an imported package. NCSIM seems to use the value of the constant from the package over the generic.
Rather than rename the generic is there a way I can force the scope to pick up the generic.

The identifier can be qualified with package or entity name in order to specify
which of the overlapping identifiers that should be used. For example with the
code:
package pkg is
constant CONST : integer := 17;
end package;
...
use work.pkg;
use work.pkg.all;
entity mdl is
generic(
CONST : integer := 42);
end entity;
architecture sim of mdl is
begin
process is
begin
report "CONST = " & integer'image(CONST);
report "pkg.CONST = " & integer'image(pkg.CONST);
report "mdl.CONST = " & integer'image(mdl.CONST);
wait;
end process;
end architecture;
The result with ModelSim is:
# ** Note: CONST = 42
# ** Note: pkg.CONST = 17
# ** Note: mdl.CONST = 42
However, the problem origins from "pollution" of the name space with use
work.pkg.all, so a cleaner solution is to avoid pollution in the first place with use work.pkg, and then force qualified names for references to identifiers in the package, except if that approach is unpractical.

Related

vhdl ERRROR: Attribute "range" requires a constrained array prefix

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;

In VHDL, Is it possible to reference a static variable using an access reference?

In VHDL, Is it possible to reference a static variable using an access reference?
Most of the examples I've seen with VHDL accesses involve allocating memory dynamically. I was curious if you can also get the access handle to a statically allocated variable. Like if I had a global integer in a particular architecture that is allocated statically, Could I assign a reference to that variable to an access type for integer?
No such thing in VHDL exists. You cannot get a "handle" to another variable for an access type. You can only create dynamic memory into an access type.
But, VHDL does have aliases. With these, you can create an alias to anything visible. And using external names (from VHDL 2008) you can create an alias to any object that is not directly visible. For example:
entity ent1
end entity ent1;
architecture arch of ent1 is
constant SOME_CONST : integer := 7;
alias my_alias : integer is SOME_CONST;
begin
process
begin
report "ent1 alias = " & to_string(my_alias);
wait;
end process;
end architecture;
entity ent2 is
end entity ent2;
architecture arch of ent2 is
begin
inst : entity work.ent1;
process
alias a is << constant inst.SOME_CONST : integer >>;
begin
report "ent2 alias = " & to_string(a);
wait;
end process;
end architecture;

VHDL null file handle

I have a procedure (testbench only, non-synthesisable) which receives data via an AXIS interface and writes it to a byte array. I also want the option to write the received data to file. To do this i've added a file handle such that any test bench using this procedure can declare a file handle and pass it to the procedure and the received data will be written to the given file via the file handle.
Here's the procedure declaration:
procedure AXI_STREAM_RECEIVER
(
-- AXI-Stream Parameters
variable PAYLOAD : inout p_byte_array;
constant SLAVE_READY_BEHAVE : in t_slave_ready_behave := always_ready;
constant READY_GAP_RANGE : in natural := 20;
constant VERIFY_TKEEP : in boolean := false;
file file_handle : text;
-- Interface Clock
signal CLK : in std_logic;
-- Master/Slave I/O
signal axis_tdata : in std_logic_vector;
signal axis_tkeep : in std_logic_vector;
signal axis_tvalid : in std_logic;
signal axis_tlast : in std_logic;
signal axis_tready : out std_logic;
-- Misc.
constant VERIFY_TLAST : in boolean := true;
constant VERBOSE : in boolean := c_verbosity_default;
constant DEBUG_SEVERITY_LEVEL : in severity_level := c_axil_debug_severity_level;
constant DEBUG_PAYLOAD_CONTENT : in boolean := false
);
As I want the write to file to be optional, I was hoping to be able to provide a 'null' file handle as a default when writing to file is not required. I've tried assigning a default but I get:
FILE interface declaration must not contain a default expression
Then i've tried assigning it to 'null' when instanced:
Illegal use of NULL literal.
But then if I leave it with no default and not assigned I get:
No feasible entries for subprogram "AXI_STREAM_RECEIVER"
Anybody know if it's possible to pass in some sort of null file descriptor?
You can achieve this using a package with generics using VHDL-2008. The file handle and procedure are declared separately within the package header. Here's an example:
library ieee;
use ieee.std_logic_1164.all;
library std;
use std.textio.all;
package gen_pkg is
generic (
PRINT_TO_FILE : boolean;
FILE_NAME : string;
FILE_MODE : file_open_kind := write_mode
);
file outfile : text;
procedure TEST_PROCEDURE;
end gen_pkg;
package body gen_pkg is
procedure TEST_PROCEDURE is
variable outline : line;
begin
write(outline,string'("TEST STRING"));
if PRINT_TO_FILE then
file_open(outfile, FILE_NAME, FILE_MODE);
writeline(outfile, outline);
file_close(outfile);
end if;
end TEST_PROCEDURE;
end gen_pkg;
I've only shown a string being written, but use any of the overloaded variants of write in the textio package depending on your required datatype or you can use the VHDL-2008 function to_string which supports conversions of all types.
Then in your testbench, create a new instantiation of the package and access procedures/functions, etc. using the instantiation name:
library ieee;
use ieee.std_logic_1164.all;
library std;
use std.textio.all;
entity tb is
end tb;
architecture arch of tb is
package gp is new work.gen_pkg
generic map (
PRINT_TO_FILE => TRUE,
FILE_NAME => "./test_file.txt",
FILE_MODE => append_mode
);
begin
process begin
for i in 0 to 4 loop
gp.TEST_PROCEDURE;
end loop;
wait;
end process;
end arch;
Please note, if you write to the file more than once, like shown in this example, file mode must be append_mode. In write_mode, the file will be overwritten everytime file_open is called. If you only write to the file once per simulation, write_mode is fine. You can also have multiple new instantiations of your generic package in multiple locations, all writing to the same file, as along as they all use append_mode for the file mode.
Here's the working example on EDA playground setup to use Aldec Riviera Pro 2017.02. A login is required to run it. You must have pop-up blocker disabled in your browser in order to download the output file to inspect. The string "TEST STRING" should be written to the file 5 times.
In VHDL 2008 and earlier, you must always connect a file object in an interface list to another file object. Accessing the object when it is not open will cause an error, but there is no way to detect if the file is open or not. VHDL2019 does add a FILE_STATE function to do this, but I assume you still need to connect it to an existing file object with no defaults allowed.
Would it be easier to pass in a string of the filepath, which can have a default of ""? If it is a null string then dont open the file.

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.

Global Package to merge several packages vhdl

I have a system described in vhdl that shall run with different configurations. For that I have put the last in different packages files. I have then a global package where I uncomment the config I want to be synthesized. I use this global package every where then to declare my entities.
But the problem is that in fact while synthesizing, types and constants declared in the config packages are not visible.
I tried to declare the "use my_package.all" in the global package file above the declaration of the global package, and I tried also inside the global package.
I mean I tried:
use work.config1.all;
package global_package is
...
end global_package;
and I tried:
package global_package is
use work.config1.all;
...
end global_package;
that is actually accepting by the synthesizer.
Does someone have a solution ? I really don't want to comment and uncomment in all my files the config I want.
Thank you!
EDIT :
For example, if I have:
file 1 :
package config1 is
constant my_variable : integer := 1;
end config1;
file 2 :
package config2 is
constant my_variable : integer := 2;
end config2;
file 3 :
use work.config1.all
-- use work.config2.all
package global is
constant another_variable : integer := 5;
end global;
file 4 :
use work.global.all
entity my_entity is
port(clk : in std_logic);
end my_entity ;
architecture Behavioral of my_entity is
signal sig1, sig2 : integer;
begin
sig1 <= another_variable; -- I can see and use here the constant "another_variable".
sig2 <= my_variable; -- Error ! I would like to have access here to the constant "my_variable" that the synthesizer can't see.
end Behavioral;
Having then these 4 files, I can't have access to "my_variable" through only "global" package. Furthermore, I would like this constant has the value given in package config1 or config2 in function of the one that is not commented.
Have you tried a context clause declaration and a reference to it? Here is one I have for reference:
context OsvvmContext is
library OSVVM ;
use OSVVM.AlertLogPkg.all ;
use OSVVM.RandomPkg.all ;
use OSVVM.CoveragePkg.all ;
use OSVVM.MemoryPkg.all ;
. . .
end context OsvvmContext ;
Then in your design, you reference it:
library osvvm ;
context osvvm.OsvvmContext ;
This way, you can edit your context clause and change the set of packages you include for your entire project. It is VHDL-2008, so for synthesis YMMV, but for simulation, it is well supported.
I don't know of a easy way to make something in one package visible by using another package. (This is possible in system-verilog using export, but that doesn't help you.)
Instead, there are various other ways that you could solve your problem. I don't exactly know what you problem is, but here is one suggestion:
package global is
constant another_variable : integer := 5;
function set_my_variable (i : integer) return integer;
constant my_variable : integer := set_my_variable(another_variable);
end global;
package body global is
function set_my_variable (i : integer) return integer is
begin
if i = 5 then
return 1;
else
return 2;
end if;
end function;
end package body global;
library IEEE;
use IEEE.std_logic_1164.all;
use work.global.all;
entity my_entity is
port(clk : in std_logic);
end my_entity ;
architecture Behavioral of my_entity is
signal sig1, sig2 : integer;
begin
sig1 <= another_variable; -- I can see and use here the constant "another_variable".
sig2 <= my_variable; -- Error ! I would like to have access here to the constant "my_variable" that the synthesizer can't see.
end Behavioral;
https://www.edaplayground.com/x/5xNd
Here I am initialising a constant using a function whose input is another constant. Then by simply editing that constant, I can change the value of lots of other constants. You could write various functions to initialise the various constants you wish to initialise.
Interestingly, such a function executes during elaboration. This can make debugging tricky. If you need to debug it, you can perhaps call the function to initialise a signal or variable, so that the function executes after time 0 rather than before it.

Resources