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.
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.
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 am seeking help as I am learning this language construct.
Here is what I have:
function int_slv(val,width: integer) return std_logic_vector is
variable R: std_logic_vector(0 to width-1):=(others=>'0')
variable b:integer:= width;
begin
if (b>32) then
b=32;
else
assert 2**bits >val report
"value too big for std_logic_vector"
severity warning
end if;
for i in 0 to b-1 loop
if val ((val/(2**i)) MOD 2 = 1) then
R(i)='1';
end if;
end loop;
return(R);
end int_slv;
In addition to 5 syntax errors, one wrong identifier and a modulo reduction expressions expressed as an element of an array as well as several sets of redundant parentheses, your modified code:
library ieee;
use ieee.std_logic_1164.all;
package int2bv_pkg is
function int_slv (val, width: integer) return std_logic_vector;
end package;
package body int2bv_pkg is
function int_slv (val, width: integer) return std_logic_vector is
variable R: std_logic_vector(0 to width-1):=(others=>'0'); -- added ';'
variable b:integer:= width;
begin
if b > 32 then
b := 32; -- ":=" is used for variable assignment
else
assert 2 ** width > val report -- width not bits
"value too big for std_logic_vector"
severity warning; -- missing semicolon at the end of assertion
end if;
for i in 0 to b - 1 loop
if val/2 ** i MOD 2 = 1 then -- not val (...)
R(i) := '1'; -- ":=" variable assign.
end if;
end loop;
return R; -- parentheses not needed
end int_slv;
end package body int2bv_pkg;
analyzes (compiles). The exponentiation operator "**" is the highest priority, the division operators "/" and "mod" are the same priority and executed in the order they are found (left to right). It's likely worthwhile learning VHDL operator precedence.
You were using "=" for variable assignment when you should have been using ":=" in two places, you were missing two semicolons and were using the identifier bits (which isn't declared in your function) where apparently you meant width.
The modified example analyzes, and hasn't been tested absent a Minimal, Complete and Verifiable example in the question.
Note that a package body is a design unit as is a package declaration. There are various other places in other design units you can introduce a function body.
You could also note the 2 ** 31 is outside the guaranteed range of an integer in VHDL equal to 2147483648, while the INTEGER value range guaranteed to be from -2147483647 to +2147483647 at a minimum.
This implies that were ever you are using a value that derived from an expression equivalent to 2 ** 31 you can incur a range error during execution (either at elaboration or during simulation).
This pretty much says you need a VHDL implementation with a larger INTEGER value range or you need to rethink what you're doing.
As a matter of course there are integer to unsigned and integer to signed functions found in package numeric_std in library IEEE.
The result of such can be type converted to std_logic_vector, and the source code can make great learning aids on how to wend through the limitations VHDL imposes. These to_signed or to_unsigned functions would be capable of dealing with the maximum value an INTEGER can hold and specify the length of the resulting array type while providing zero or sign filling for array lengths greater than the INTEGER's binary value. That utility extends to clipping using length as well.
VHDL -2008 package numeric_std_unsigned contains a function To_StdLogicVector that does what your int_slv function is intended to do although limited to a NATURAL range for the integer type input.
As #user1155120 has already indicated, the VHDL-2008 package numeric_std_unsigned has a builtin to_stdlogicvector. And #user1155120 already pointed out the to_signed and to_unsigned in numeric_std are available as well.
So, to expand on the previous answer, you can do:
constant C : integer := -6817563;
constant C_VEC : std_logic_vector(31 downto 0) := std_logic_vector(to_signed(c, 32));
And this mechanism will accept the full range of integer. You can also use to_unsigned, but this is limited to the range of natural.
I am reading two hex numbers from a text file and I want to be able to subtract the two numbers and place the result into another variable how would I go about doing this? Is it possible to make a function to do this that I can then place in a package file and reference so that my code is more readable and less cluttered?
many thanks,
For conversion of line to unsigned, VHDL-2008 provides a hread procedure in then numeric_bit package. A function that takes string and returns natural could look like:
library ieee;
use ieee.numeric_bit.all;
library std;
use std.textio.all;
...
function hex_to_nat(s : string) return natural is
variable line_v : line;
variable value_v : unsigned(4 * s'length - 1 downto 0); -- Bits to match value in hex
begin
line_v := new string'(s);
hread(line_v, value_v); -- Assertion in case of conversion error
deallocate(line_v); -- Avoid memory leak
return to_integer(value_v); -- Assertion in case of conversion error
end function;
If the text read from the file is already of line type, then just use the hread procedure directly.
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.