ada invalid index constraint - matrix

I defined a matrix type in ada like this:
type Matrix_Type is array(Natural range <>, Natural range <>) of Item_Type;
in order to apply some transformations to an input matrix, I need to define a matrix slice in a function.
I tried that by doing it the following way
procedure Do_Stuff(M: Matrix_Type) is
-- c needs to be half as big as the input matrix M
C: Matrix_Type(A'Length / 2, A'Length / 2);
begin
...
end Do_Stuff;
However, compiling fails with the error: invalid index constraint which I don't quite understand, since Putting A'Length returns a number as A'Length /2 does. If I declare C using fixed numbers like that
C: Matrix_Type(2,2);
everything works fine.
What is the error in that case, the only possible case in which I would understand it kind of would be if I pass some uninitialized Matrix to the function, and even that doesn't quite make sense to me.

The index constraint for the matrix C should be a range:
procedure Do_Stuff(M: Matrix_Type) is
-- C needs to be half as big as the input matrix M
C : Matrix_Type(M'First .. M'Length / 2, M'First .. M'Length / 2);
begin
…
end Do_Stuff;
For non-square matrices, you can use the Operations of Array Types to specify a particular index:
C : Matrix_Type(M'First(1) .. M'Length(1) / 2, M'First(2) .. M'Length(2) / 2);

Related

Invalid Floating Point Operation?

I am a beginner in Pascal. I made this simple calculating program and keep getting exitcode : 207 message when running this code. Some website says that it is because of the invalid floating point operation. So I suppose its because of the division of zero. But I don't know how to avoid that.
uses crt;
var
a, b, c, d, e, f : real;
begin
c := a + b;
d := a - b;
e := a * b;
f := a / b;
writeln(' Basic Math Operation ');
writeln('Write First Number a ');
readln(a);
writeln('Write Second Number b ');
readln(b);
writeln('The addition of a + b =', c);
writeln('The substraction of a - b =', d);
writeln('The multiplication of a x b =', e);
writeln('The division of a / b =', f);
readln;
end.
I also tried to add this but keep getting the same exitcode : 207
if (b=0) then
writeln(' Can't do division by 0 !')
else
writeln('The division of a / b =', f);
or this one that i found on a forum
except on EDivByZero do ShowMessage('Can't do division by 0 !');
What shall i do???
Assuming you are using Free Pascal:
By default, simple variables in Pascal are not initialized after their declaration. Any assumption that they contain 0 or any other default value is erroneous: They can contain rubbish. To remedy this, the concept of initialized variables exists. The difference with normal variables is that their declaration includes an initial value, as can be seen in the diagram in the previous section.
Remark 2 exceptions to this rule exist:
Managed types are an exception to this rule: Managed types are always initialized with a default value: in general this means setting the reference count to zero, or setting the pointer value of the type to Nil. See section 3.9, page 226
Global variables are initialized with the equivalent of zero.
a, b, c, d are initialised to 0 at the start of the program. Therefore f:=a/b produces division by zero error. You should move the line readln(a) and readln(b) at the start of the program to assign a value to the variables before use. Also check whether b is inputted as 0 to avoid similar issues.

Can I define a for..generate that doesn't generate anything for edge cases?

Can I define a for..generate from 0 to -1 that just doesn't generate anything? BLOCK_WIDTH is a generic, which may be 0 for some edge cases (which is fine, we just don't need to generate anything).
Gen_Block: if BLOCK_WIDTH /= 0 generate -- Do I need this?
Gen_Bits: for i in 0 to BLOCK_WIDTH - 1 generate
-- Other stuff here.
end generate;
end generate;
Is the enclosing if generate statement necessary? No.
For a minimum complete and verifiable example:
entity foo is
end entity;
architecture fum of foo is
constant BLOCK_WIDTH: natural := 0;
begin
Gen_Bits:
for i in 0 to BLOCK_WIDTH - 1 generate
-- Other stuff here.
end generate;
end architecture;
This analyzes, elaborates and runs which tells us it syntactically and semantically legal VHDL.
For the case of BLOCK_WIDTH = 0 we see the parameter specification of the for generate statement condition would have the range 0 to BLOCKWIDTH - 1 (or 0 = 1 = -1).
IEEE Std 5.2 Scalar types, 5.2.1. General, para 3:
A range specifies a subset of values of a scalar type. A range is said to be a null range if the specified subset is empty.
So how do we determine if the subset is empty?
11.8 Generate statements para 5:
The discrete range in the generate parameter specification of a for generate statement shall be a static discrete range; similarly, each condition in an if generate statement shall be a static expression.
So what happens in a discrete range?
5.3.2 Array types, 5.3.2.1 para 2 (excerpted):
discrete_range ::= *discrete_*subtype_indication | range
5.2 Scalar types, 5.2.1 para 2 (excerpted):
range ::=
range_attribute_name
| simple_expression direction
simple_expression direction ::= to | downto
para 4:
The range L to R is called an ascending range; if L > R, then the range is a null range. The range L downto R is called a descending range; if L < R, then the range is a null range. L is called the left bound of the range, ...
para 7:
If a range constraint is used in a subtype indication, the type of the expressions (likewise, of the bounds of a range attribute) shall be the same as the base type of the type mark of the subtype indication. A range constraint is compatible with a subtype if each bound of the range belongs to the subtype or if the range constraint defines a null range. Otherwise, the range constraint is not compatible with the subtype.
(And each bound of the range for i is compatible with the base type of the range expression, which is integer).
So guess what? The VHDL code without the if generate statement enclosing the for generate statement is legal VHDL, there are no values of i in the subset of integer values that can cause elaboration of any enclosed concurrent statements or declarations.
So no, you don't need the enclosing if generate statement.

How to set VHDL vector size based on the log of a constant

I would like to know what is corresponding VHDL code for $clog2(DATA_WIDTH) , for example in this line:
parameter DATA_OUT_WIDTH = $clog2(DATA_WIDTH)
and also for this sign " -: " in this example
if ( Pattern == In[i_count-:PATTERN_WIDTH] )
I will appreciate if anyone can help me.
You can do something like this
constant DATA_OUT_WIDTH : positive := positive(ceil(log2(real(DATA_WIDTH))));
or define a clog2 function encapsulating that expression. ceil and log2 can be found in math_real
use ieee.math_real.all;
In VHDL you can just specify the full range, for example
foo(i_count to i_count + 7)
foo(i_count downto i_count - 7)
Don't use In as an identifier though, it's a reserved word in VHDL.
In addition to Lars example you can easily write a function for finding the ceiling log 2 to determine the number of element address 'bits' necessary for some bus width. Some vendors or verification support libraries provide one already.
The reason there isn't a predefined function in an IEEE library already is expressed in Lars answer, you tend not to use it much, you can assign the value to a constant and an expression can be cobbled together from existing functions.
An example clog2 function
A borrowed and converted log2 routine from IEEE package float_generic:
function clog2 (A : NATURAL) return INTEGER is
variable Y : REAL;
variable N : INTEGER := 0;
begin
if A = 1 or A = 0 then -- trivial rejection and acceptance
return A;
end if;
Y := real(A);
while Y >= 2.0 loop
Y := Y / 2.0;
N := N + 1;
end loop;
if Y > 0.0 then
N := N + 1; -- round up to the nearest log2
end if;
return N;
end function clog2;
The argument A type NATURAL prevents passing negative integer values. Rounding is strict, any remainder below 2.0 causes rounding up.
Note that because this uses REAL and uses division it's only suitable for use during analysis and elaboration. It's a pure function.
You could note Lars example:
constant DATA_OUT_WIDTH : positive := positive(ceil(log2(real(DATA_WIDTH))));
has the same constraints on use for analysis (locally static) and elaboration (globally static). REAL types are generally not supported for synthesis and floating point operations can consume lots of real estate.
The if condition
if ( Pattern == In[i_count-:PATTERN_WIDTH] )
Is a base index (an lsb or msb depending on ascending or descending declared bit order) and a width.
See IEEE Std 1800-2012 (SystemVerilog), 11.5.1 Vector bit-select and part-select addressing.
An indexed part-select is given with the following syntax:
logic [15:0] down_vect;
logic [0:15] up_vect;
down_vect[lsb_base_expr +: width_expr]
up_vect[msb_base_expr +: width_expr]
down_vect[msb_base_expr -: width_expr]
up_vect[lsb_base_expr -: width_expr]
The msb_base_expr and lsb_base_expr shall be integer expressions, and the width_expr shall be a positive constant integer expression. Each of these expressions shall be evaluated in a self-determined context. The lsb_base_expr and msb_base_expr can vary at run time. The first two examples select bits starting at the base and ascending the bit range. The number of bits selected is equal to the width expression. The second two examples select bits starting at the base and descending the bit range.
In VHDL terms this would be a slice with bounds determined from the high index and a width by subtraction.
PATTERN_WIDTH can be globally static (as in a generic constant) as well as locally static (a non-deferred constant). i_count can be variable.
Depending on the declared range of In for example:
constant DATAWIDTH: natural := 8;
signal In_in: std_logic_vector (31 downto 0);
The equivalent expression would be
if Pattern = In_in(i_count downto i_count - DATAWIDTH - 1) then
Note that if the slice length or i_count is less than DATAWIDTH - 1 you'll get a run time error. The - 1 is because In_in'RIGHT = 0.
Without providing the declarations for In (or Pattern) and DATAWIDTH a better answer can't be provided. It really wants to be re-written as VHDL friendly.
Note as Lars indicated in is reserved word (VHDL is not case sensitive here) and the name was changed.

Comparing reals in VHDL

My current method of comparing two reals (after calculations) is to take the difference and cast to an integer and compare to 0, for example (just to highlight the problem, example might work in simulator)
variable a : real := 0.1;
constant epsilon : real := 1.0E-5; -- Whatever accuracy needed, not too low though
a := a + 5.3;
assert a = 5.4; -- Yields intermitent errors
assert integer(a - 5.4) = '0'; -- Erroneous if 4.8 < a < 5.9 due to cast rounding
assert abs(a - 5.4) < epsilon; -- Will work everytime, but seems a bit forced
The reason for this way is that I got a lot of assertion errors in an testbench I wrote (a tad more complext then the example code). I was accounting these errors as floating point errors in GHDL simulator. Is there a better way to compare two reals to each other, like using machine epsilon, or any build in methods?
As indicated by #Philippe, comparison of reals requires some margin to account for limited precision and accumulated errors in the least significant bits. Using a simple epsilon value is one common way to do this but it has a limitation in that its value is absolute in relation to the numbers being compared. You need to know in advance the expected values you're comparing to pick a suitable epsilon.
If the set of numbers you need to compare covers a wide range of magnitudes you end up with an epsilon that is too large for properly comparing small values. In this situation you'd want a small epsilon when comparing small reals and a larger epsilon for larger numbers. This is accomplished by using a comparison that accounts for relative error.
This page gives a good overview of a method that allows comparison of reals using relative error rather than absolute error. The following function is an implementation of the relative comparison in VHDL:
-- Adapted from: http://floating-point-gui.de/errors/comparison/
function relatively_equal(a, b, epsilon : real) return boolean is
begin
if a = b then -- Take care of infinities
return true;
elsif a * b = 0.0 then -- Either a or b is zero
return abs(a - b) < epsilon ** 2;
else -- Relative error
return abs(a - b) / (abs(a) + abs(b)) < epsilon;
end if;
end function;
Here the epsilon parameter is a fraction that specifies the number of significant digits to compare for relative equality.
-- Compare for relative equality to three significant digits
-- These are all considered equal while using the same epsilon parameter
assert relatively_equal(1.001, 1.002, 1.0E-3) report "1.001 != 1.002";
assert relatively_equal(100.1, 100.2, 1.0E-3) report "100.1 != 100.2";
assert relatively_equal(1001.0, 1002.0, 1.0E-3) report "1001 != 1002";
-- Compare for relative equality to four significant digits
-- This will raise the assertion
assert relatively_equal(1.001, 1.002, 1.0E-4) report "1.001 != 1.002";
This question is generic to any programming language that uses "real" values (a.k.a. floating point numbers).
The standard way to compare reals in automatic tests is to define an small value epsilon. Then check that the absolute difference between your two reals is less than epsilon. You can define your own procedure assertEqual(x,y, epsilon) if you want to write concise test benches.
procedure assertEquals(
x, y : real; epsilon : real := 1.0E-5;
message : string := "";
level : severity_level := error) is
begin
assert (abs (x - y) < epsilon) report message severity level;
end procedure assertEquals;

Mod error due to input vector in vhdl

m<=(s-1) mod 2
Here 'm' is a signal while s is an input vector
While trying to implement the code I am getting an error "mod cannot have such operands in this context"
Error might be due to trying to get mod of vector value.
Is there any way to either equate the vector to an integer value or correct the error via some other method?
Since mod 2 is basically just extracting the last bit of the vector and the -1 is just negating this, why not just do:
m <= not s(0);
I assume 's' is defined as a 'std_logic_vector'. You better/should use 'unsigned' or 'signed' from the 'ieee.numeric_std' library for those operators. You can convert your 'std_logic_vector' to 'signed' or 'unsigned' with a typecast. E.g. unsigned(s).
Anyhow: Sonicwave's solution is cleaner.
Either use an integer for the vector instead (ie change the type of the signal) or convert it to an integer before moding
use ieee.numeric_std.all;
i := to_integer(unsigned(s));
m := (i-1) mod 2;

Resources