How to return record with unconstrained 2d array from a function - vhdl

I have a record type(REC) which contains an element of type VECTOR which is an unconstrained 2d array of STD_LOGIC:
package TEST is
type VECTOR is array (NATURAL range <>, NATURAL range <>) of STD_LOGIC;
type REC is record
data : VECTOR;
end record REC;
function con(
a : REC;
b : REC)
return REC;
end package TEST;
When declaring the body of the con function I want to specify the size of the REC.data array like so:
package body TEST is
function con(
a : REC;
b : REC)
return REC is variable r : REC(
data(a.data'length(1) + b.data'length(1) - 1 downto 0, a.data'length(2) - 1 downto 0));
begin
-- . . . do things
end function con;
end package body TEST;
but in the line where I attempt to set the size of data it Vivado throws the following error:
Sliced name is allowed only on single-dimensional arrays
Does this mean I cannot have an unconstrained 2d arraign in a record or is there a different method for defining the size of it in the con function ?
---- EDIT ----
Since I now understand that it is not possible to use 2d arrays in this context what method should I use to create a function which:
Takes two 2d arrays (or arrays of arrays) of size [x][y] and [z][y] as inputs
Outputs an array of size [x+z][y]
With both input arrays being unconstrained and the output array being constrained to size [x+z][y]
And all arrays (input and return) be a record type

user1155120 I don't think I fully understand what you are trying to say. Are you saying my code is not
a minimal reproducible example, because except for me forgetting to include the STD_LOGIC library
the code reproduces the problem when I paste it into Vivado, and it is about as minimal as I can get it.
Or are you saying that the code you linked as this works works for you, because at least in my
Vivado it still throws the same error ? – Mercury 4 hours ago
The original comment was meant for Tricky. There's a missing return statement in the function con which would prevent use in an example.
It isn't clear if record constraints (a -2008 feature) are supported in Vivado Simulator. In Vivado Synthesis Guide UG901 2020.1 we see all sorts of wonderful uses of record types from everything to inferring ram to record elements of record types. Xilinx has been busy.
It'd seems odd if unconstrained elements in record type declarations were supported but not record constraints (they're pretty much a package deal, pun aside). Note the comment called it a -2008 feature.
A record constraint is limited to supply the constraint of an element or subelement that is of an unconstrained type (typically arrays). VHDL has always been capable of supplying multi-dimensional array constraints. The language of the standard is particular based on the flexibility of the syntax.
This code is VHDL -2008 compliant and provides your record constraint:
library ieee; -- ADDED for MCVe
use ieee.std_logic_1164.all; -- ADDED
package TEST is
type VECTOR is array (NATURAL range <>, NATURAL range <>) of STD_LOGIC;
type REC is record
data: VECTOR;
end record REC;
function con (a: REC; b: REC) return REC;
end package TEST;
package body TEST is
function con (a: REC; b: REC) return REC is
variable r:
REC ( -- record constraint:
data (
natural range a.data'length(1) + b.data'length(1) - 1 downto 0,
natural range a.data'length(2) - 1 downto 0
)
);
begin
-- . . . do things
return r; -- ADDED required return statement
end function con;
end package body TEST;
You'll note the changes to the record constraint from yours is the addition of natural range before each range of the element data constraint.
From IEEE Std 1076-2008 5.3.3 Record types:
record_constraint ::=
    ( record_element_constraint { , record_element_constraint } )
record_element_constraint ::= record_element_simple_name element_constraint
From 6.3 Subtype declarations:
element_constraint ::=
      array_constraint
    | record_constraint
Here the element data is an array so an array_constraint is appropriate.
From 5.3.2 Array types, 5.3.2.1:
array_constraint ::=
    index_constraint [ array_element_constraint ]
    | ( open ) [ array_element_constraint ]
Because element data array elements are scalar (enumeration type STD_LOGIC) we follow index_constraint.
index_constraint ::= ( discrete_range { , discrete_range } )
discrete_range ::= discrete_subtype_indication | range
The code shown above uses a discrete subtype indication for the index ranges of the element data dimensions and successfully analyzes (compiles).
From 5.2.2 Scalar types, 5.2.2.1:
range ::=
      range_attribute_name
    | simple_expression direction simple_expression
direction ::= to | downto
The constraint in the question uses a range with simple expressions and direction.
So why did it produce the error message about multi-dimensional slices?
In 9. Expressions, 9.1 the BNF, simple_expression -> term -> factor -> primary -> name.
In 8. Names, 8.1 name -> slice_name, only multi-dimensional slices are not allowed semantically in 8.5 Slice names who's BNF tells us it's syntactically valid:
slice_name ::= prefix ( discrete_range )
The prefix of a slice shall be appropriate for a one-dimensional array object. The base type of this array type is the type of the slice.
and semantically the prefix data is not appropriate for a one-dimensional array object.
These comments provide bit more context for the problem although it isn't clear which version the record constraint you used in the reported eventual success:
#Mercury when you add a (VHDL) file to Vivado, it's by default set to use VHDL 93, but not 2008. Go
to the property Window and change the file type from VHDL to VHDL 2008. I'm not sure why it
prints the wrong error message in your case. (Vivado likes to confuse users with wrong error messages
...). Anyhow, it should have reported your feature is only supported in 2008 mode. – Paebbels 3 hours
ago
#Paebbels Thank you, that fixed the problem, maybe add it as a sub note to your response so I can
mark it as accepted answer. You just saved me hours of frustration. And I'm already getting familiar with
Vivado's shenanigans, my Favorit one of which is "ERROR close to ..." which has to be one of the most
useless error messages I have experience in a long time :) – Mercury 3 hours ago
As far as detecting -2008 source, there are no -1993 syntax errors and no -2008 new reserved word, delimiters, separators or graphics characters in either the primary unit or the secondary.
That leaves you at the mercy of semantic analysis which failed. You could also note the unconstrained record element wasn't reported during analysis of the package declaration. It occurred during evaluation of the variable r. All declared objects are required to be constrained. VHDL doesn't have a recital of all features, semantics can be restrictive as well. It's legal in places to have unconstrained elements and objects.
Associating semantics rules found in the text of the standard with an textual element of the particular declaration or statement can be tough and the squeaky wheel gets the lubricant. Record constraints are relatively new to VHDL implementations.
The problem appears to have been one of tool familiarity.

This is the definition of row and column merges from PoC's vectors package, see lines starting at 359:
function slm_merge_rows(slm1 : T_SLM; slm2 : T_SLM) return T_SLM is
constant ROWS : positive := slm1'length(1) + slm2'length(1);
constant COLUMNS : positive := slm1'length(2);
variable slm : T_SLM(ROWS - 1 downto 0, COLUMNS - 1 downto 0);
begin
for i in slm1'range(1) loop
for j in slm1'low(2) to slm1'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(i, j) := slm1(i, j);
end loop;
end loop;
for i in slm2'range(1) loop
for j in slm2'low(2) to slm2'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(slm1'length(1) + i, j) := slm2(i, j);
end loop;
end loop;
return slm;
end function;
function slm_merge_cols(slm1 : T_SLM; slm2 : T_SLM) return T_SLM is
constant ROWS : positive := slm1'length(1);
constant COLUMNS : positive := slm1'length(2) + slm2'length(2);
variable slm : T_SLM(ROWS - 1 downto 0, COLUMNS - 1 downto 0);
begin
for i in slm1'range(1) loop
for j in slm1'low(2) to slm1'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(i, j) := slm1(i, j);
end loop;
for j in slm2'low(2) to slm2'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(i, slm1'length(2) + j) := slm2(i, j);
end loop;
end loop;
return slm;
end function;
The definition of T_SLM is:
type T_SLM is array(natural range <>, natural range <>) of std_logic;
Currently, I see no problem in nesting this code in another layer like your unconstrained record.
Edit:
Thie code above requires VHDL 2008 to be enabled in Vivado.
When VHDL files are added to Vivado, it's by default set to use VHDL 93, but not 2008. Go to the property Window and change the file type from VHDL to VHDL 2008``.
The printed error message is misleading and points to a false feature being used. The correct message should be it's a VHDL-2008 feature, please enable it.

Related

VHDL Case choice is not locally static

This code works with some tools
Aldec Riviera Pro
but not others
GHDL ( ERROR choice must be locally static expression)
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY INSTRUCTION_PROCESSOR IS
PORT (
clk : IN std_logic;
instruction : IN INTEGER
);
END ENTITY INSTRUCTION_PROCESSOR;
ARCHITECTURE behavioural OF INSTRUCTION_PROCESSOR IS
TYPE INSTRUCTION_t IS RECORD
instr : INTEGER;
cycles : INTEGER;
END RECORD;
CONSTANT CMD_A : INSTRUCTION_t := (instr => 0, cycles => 5);
CONSTANT CMD_B : INSTRUCTION_t := (instr => 1, cycles => 3);
BEGIN
PROCESSOR : PROCESS (clk)
VARIABLE loop_cycles : INTEGER := 0;
BEGIN
IF clk'event AND clk = '1' THEN
CASE instruction IS
WHEN CMD_A.instr =>
loop_cycles := CMD_A.cycles;
WHEN CMD_B.instr =>
loop_cycles := CMD_B.cycles;
WHEN OTHERS =>
NULL;
END CASE;
END IF;
END PROCESS;
END ARCHITECTURE;
https://www.edaplayground.com/x/jYD
since CMD_A and CMD_B are declared as constant records i would expect this to work...
any words of wisdom or is it just a bad idea?
I'm not sure the ghdl-0.35 version on EDA playground is up to handling --std=08 (-2008) for this issue without trying it. A recent ghdl-0.37-dev version shows it works:
ghdl -a --std=08 instruction_processor.vhdl
ghdl -e --std=08 tb
instruction_processor.vhdl:68:8:error: for default port binding of component instance "uut":
instruction_processor.vhdl:68:8:error: type of signal interface "instruction" declared at line 56:9
instruction_processor.vhdl:68:8:error: not compatible with type of port "instruction" declared at line 9:9
instruction_processor.vhdl:68:8:error: signal interface "cycles" has no association in entity "instruction_processor"
ghdl:error: compilation error
even if the testbench and/or entity header needs a bit of work. Both INSTRUCTION_PROCESSOR and TB are located in the same design file used above.
The IEEE Std 1076-2008 revision changed some definitions in 9.4.2 Locally static primaries
9.4.2 Locally static primaries
An expression is said to be locally static if and only if every operator in the expression denotes an implicitly defined operator or an operator defined in one of the packages STD_LOGIC_1164, NUMERIC_BIT, NUMERIC_STD, NUMERIC_BIT_UNSIGNED, or NUMERIC_STD_UNSIGNED in library IEEE, and if every primary in the expression is a locally static primary, where a locally static primary is defined to be one of the following:
...
m) A record aggregate in which all expressions in element associations are locally static expressions.
...
Prior to -2008 a an aggregate could not be locally static. An aggregate is an expression which is 'a formula that defines the computation of a value', previously always globally static for a constant declaration value expression.
Allowing certain expressions to be locally static comes from the VHDL-200x effort producing the -2008 revision (Fast Track Proposal FT-22). The idea is expressions with locally static primaries that produce values from basic or predefined operations including those found in IEEE library packages listed above are implemented as pure functions and are not dependent on elaboration. To avoid confusion a procedure call is a statement.
Analyzing your code with Aldec Riviera Pro used a -2008 compliant flag according to the EDA playground session from your comment:
Should an earlier revision of the standard be required due to tool chain constraints either the case statement can be replaced by an if statement or a concurrent conditional assignment statement which implies and if statement equivalent. A selected signal assignment statement on the other hand implies a case statement and conforms to the same semantics.
Try to put constraint into the integer.
instruction : IN INTEGER RANGE 0 TO ...;

Increment enumeration type in VHDL

In vhdl I can define my own enumeration type and create a signal of this type:
type tp is (red,green,blue,yellow);
signal sg: tp := red;
But now I want a for loop to run over all of these states. Something like
for i in sg'min to sg'max loop
<something>
end loop;
In c++ there are iterators for this purpose. But in VHDL all I can find is sg'pos that converts the signal to a number that I can increment. But I cannot seem to find a way to convert the number back to a signal.
This is what you need:
for i in tp'left to tp'right loop
<something>
end loop;
`left and `right are called type attributes. They are useful in your testbench, but not recommended for your design. This is because you the synthesiser may change the order of the enumerations, which might cause you problems.
You can specify the type of the loop parameter where the discrete range is a range of values of a specified scalar type:
entity enum is
end entity;
architecture enum_range of enum is
type tp is (red,green,blue,yellow);
signal sg: tp := red;
begin
process (sg)
begin
for i in tp range red to yellow loop
if sg = i then
report "sg = " & tp'image(sg);
end if;
end loop;
end process;
end architecture;
This produces:
enum.vhdl:12:17:#0ms:(report note): sg = red
TL;DR explanation
IEEE Std 1076-2008 10.10 Loop statement
iteration_scheme ::=
while condition
| for loop_parameter_specification
parameter_specification ::=
identifier in discrete_range
and
For a loop statement with a for iteration scheme, the loop parameter specification is the declaration of the loop parameter with the given identifier. The loop parameter is an object whose type is the base type of the discrete range. Within the sequence of statements, the loop parameter is a constant. Hence, a loop parameter is not allowed as the target of an assignment statement. Similarly, the loop parameter shall not be given as an actual corresponding to a formal of mode out or inout in an association list.
For the execution of a loop with a for iteration scheme, the discrete range is first evaluated. If the discrete range is a null range, the iteration scheme is said to be complete and the execution of the loop statement is therefore complete; otherwise, the sequence of statements is executed once for each value of the discrete range (subject to the loop not being left as a consequence of the execution of a next statement, an exit statement, or a return statement), after which the iteration scheme is said to be complete. Prior to each such iteration, the corresponding value of the discrete range is assigned to the loop parameter. These values are assigned in left-to-right order.
5.3.2 Array types, 5.3.2.1 General
discrete_range ::= discrete_subtype_indication | range
5.3.2.2 Subtype indications
subtype_indication ::=
[ resolution_indication ] type_mark [ constraint ]
constraint ::=
range_constraint
| array_constraint
| record_constraint
5.2 Scalar types 5.2.1 General
range_constraint ::= range range
range ::= range_attribute_name
| simple_expression direction simple_expression
direction ::= to | downto
It helps to understand how defining a range as the discrete range works. Without specifying a subtype indication in the discrete range the type is derived from the simple expressions in the range. The type of a numeric literal (9.3.2 Literals) is universal_integer convertible to type integer. The type can also be supplied by attribute as Matthew Taylor shows. Only dipping a toe in simple_expression (9.1) term -> factor -> primary, a primary can be a name (attribute name, 8.6) or a literal.
BNF other than found in Annex C (informative) Syntax summary, is normative.

VHDL initialize signal with maximum value of type

I have this definition:
subtype sample_t is signed(SAMPLE_WIDTH-1 downto 0);
Now in the code I want to set a signal to the maximum value of sample_t divided by 2:
signal max_sample : sample_t;
max_sample <= to_signed(max_sample'<some attribute>/2,max_sample'LENGTH);
I've looked at attributes sample_t'HIGH and sample_t'RIGHT but these seem to return the highest subscript of the array.
From this list: https://www.csee.umbc.edu/portal/help/VHDL/attribute.html
T'HIGH is the highest value of type T.
A'HIGH is the highest subscript of array A or constrained array type.
How to use the first definition on sample_t?
One of the commenters suggestions:
max_sample <= (max_sample'LEFT => '0', others => '1');
works. But this:
max_sample <= (max_sample'LEFT => '0', others => '1')/2;
fails with "OTHERS is illegal aggregate choice for unconstrained target".
why this error?
In VHDL, signed is an array type, not an integer. The core language only knows that it is a collection of std_logic objects. It's interpretation as a number is only by convention introduced by the numeric_std library functions defining the operators and type casts for signed. As such, integer specific attributes aren't going to work on an array type.
The reason why your last attempt at division fails is that the aggregate expression forming the dividend doesn't yet have a fully determined range due to the others. The aggregate is still just an intermediate temporary and can't pick up its length from max_sample. That prevents the division operator from compiling.
It will compile if you use a fully constrained range:
max_sample <= (max_sample'high => '0', max_sample'high-1 downto max_sample'low => '1') / 2;
Or if you use a qualified expression:
max_sample <= sample_t'(max_sample'high => '0', others => '1') / 2;
An alternate solution is just to subtype integer instead of using signed. Then you can use it in a more integery way:
constant SAMPLE_T_MAX : integer := 2**(SAMPLE_WIDTH-1)-1;
subtype sample_t is integer range -SAMPLE_T_MAX-1 to SAMPLE_T_MAX;
max_sample <= sample_t'high; -- Assuming that the "divide by 2" was just to avoid the sign bit
This will not work if sample_t_max exceeds the largest integer size your tooling supports which is still typically 32-bits including the sign. Also, for practical reasons, it is best not to use integer types for signals that will be exposed on the top level port after synthesis.
Otherwise you have to work within the limitations of using array types for numerics. Your options are to resort to bit twiddling as above or just directly compute the max value similarly to the integer subtype:
constant SAMPLE_T_MAX : integer := 2**(sample_t'length-1)-1;
max_sample <= to_signed(SAMPLE_T_MAX, max_sample'length);
The accepted answer from Kevin Thibedeau could not be readily reconciled with the actual question (why this error?). The answer can be explained in terms of the VHDL standard.
First a Minimum, Complete, and Verifiable example can be constructed for the question:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity foo is
end entity;
architecture fum of foo is
constant SAMPLE_WIDTH: natural := 42; -- pick a number
subtype sample_t is signed(SAMPLE_WIDTH-1 downto 0);
signal max_sample : sample_t;
begin
-- max_sample <= (max_sample'LEFT => '0', others => '1'); -- analyzes
max_sample <= (max_sample'LEFT => '0', others => '1')/2; -- Doesn't analyze
end architecture;
Because we're dealing with semantic rules during analysis (compile) the example doesn't have to do anything besides replicate the error. Error messages aren't standardized in VHDL and will vary by implementation.
The semantics for using an others choice in an aggregate:
IEEE Std 1076-2008 9.3 Aggregates, 9.3.3 Array aggregates, para 7 (in part):
The index range of an array aggregate that has an others choice shall be determinable from the context. That is, an array aggregate with an others choice shall appear only in one of the following contexts:
...
e) As a value expression in an assignment statement, where the target is a declared object (or member thereof), and either the subtype of the target is a fully constrained array subtype or the target is a slice name
This is why the first example (commented out) analyzes. sample_t is a fully constrained subtype, see 5. Types, 5.1 General the definition of fully constrained, para 6 (in part):
A composite subtype is said to be fully constrained if:
-- It is an array subtype with an index constraint and the element subtype either is not a composite subtype or is a fully constrained composite type, or
...
Where the sample_t element base type is std_ulogic and the subtype has an index constraint.
Back to the second example.
We don't satisfy rule e), the aggregate isn't a value expression for the assignment statement, it's an operand for the division operator defined by the "/" function for overload in IEEE package numeric_std:
-- Id: A.25
function "/" (L : UNRESOLVED_SIGNED; R : INTEGER) return UNRESOLVED_SIGNED;
-- Result subtype: UNRESOLVED_SIGNED(L'LENGTH-1 downto 0)
-- Result: Divides an UNRESOLVED_SIGNED vector, L, by an INTEGER, R.
-- If NO_OF_BITS(R) > L'LENGTH, result is truncated to L'LENGTH.
(For earlier revisions of numeric_std the parameter and result types would be SIGNED instead of UNRESOLVED_SIGNED, -2008 formally defines how resolution functions of composite types drivers are defined.)
Because the rules of 9.3.3 paragraph 7 are inclusive instead of exclusive we
need to find a rule that allows us to use the aggregate, and one is readily identified:
i) As the operand of a qualified expression whose type mark denotes a fully constrained array subtype
We can use a qualified expression:
max_sample <= sample_t'(max_sample'LEFT => '0', others => '1')/2;
And this analyzes (compiles) successfully.
To clarify the value expression being assigned to max_sample is the result of division by 2 which uses an operator overload and who's function does not return a constrained subtype. (UNRESOLVED_SIGNED or SIGNED is not constrained).
The reason why there are inclusive rules is to allow the code for associating values with elements of an aggregate to be determined at analysis time (compile time). You'd find by examining previous revisions of the VHDL standard that the list of inclusive rules has been expanded.
The answer to your question with respect to the second example:
max_sample <= (max_sample'LEFT => '0', others => '1')/2;
is that the elements of the aggregate can't be identified without knowing the subtype from context.
If you were to look at the output of the parser producing an abstract syntax tree used for semantic analysis the right hand side expression in the assignment statement can be expressed hierarchically. (11.6 Concurrent signal assignment statements, the waveform is comprised of one or more waveform elements, see 10.5.2 Simple signal assignments, 10.5.2.1 General, a waveform element can contain a value expression, see 10.5.2.2 Executing a simple assignment statement, 9. Expressions, 9.1 General the BNF.)
Using inclusive rules alleviates the need of traversing the expression hierarchy and calculating the subtype of the aggregate (an operand) during analysis and would require semantic characterization of the "/" function not required by the standard. You can also construct cases where the subtype can't be readily ascertained by characterization at analysis time. The result is the rules found in 9.3.3 Array aggregates paragraph 7.
The qualified expression provides the subtype directly.

Convert enum type to std_logic_vector VHDL

I want to know if it is possible to convert a enum type, like FSM states to std_logic_vector or integer. I'm doing a testbench with OSVVM for a FSM and I want to use the scoreboard package to automatically compare the expected state with the actual one.
Thanks!
To convert to integer, use:
IntVal := StateType'POS(State) ;
From there, it is easy to convert to std_logic_vector, but I prefer to work with integers when possible as they are smaller in storage than std_logic_vector. For verification, it will be easier if you start to think more about integers when the value is less than 32 bits.
If you need it as std_logic_vector, using only numeric_std you can:
Slv8Val := std_logic_vector(to_unsigned(IntVal, Slv8Val'length)) ;
For verification, I liberally use numeric_std_unsigned, so the conversion is a easier:
Slv8Val := to_slv(IntVal, Slv8Val'length) ;
In the event you have an integer and want to convert it back to a enumerated value, you can use 'VAL.
State := StateType'VAL(IntVal) ;
In OSVVM, we use records with resolved values to create a transaction interface. We have a resoled types for integers (osvvm.ResolutionPkg.integer_max). We transfer enumerated values through the record using 'POS (as we put it in) and 'VAL (as we get it out).
Note don't confuse 'VAL with 'VALUE. 'VALUE converts a string to a value - opposite to 'IMAGE.
You of course learn all of this in SynthWorks' OSVVM class :).
Maybe like this...
function my_func(inp : t_my_enum) return integer is
begin
case inp is
when stateA =>
return 1;
when stateB =>
return 2;
when others =>
return 0;
end case;
end function my_func;
... <= my_func(stateB);`

My sorting algorithm runtime errors

I developed the following sorting algorithm but there are some run time errors that I cant figure out. The program terminates when it comes to the part of filling the array. I'm still a beginner in ada so I couldn't figure out where the problem is...
With Ada.Text_IO;
With Ada.Integer_Text_IO;
Use Ada.Integer_Text_IO;
Use Ada.Text_IO;
Procedure sort is
n,i,x : Integer;
-- Max_Heapify Function...
Procedure Max_Heapify ( i, n : integer) is
j, Temp : Integer;
begin
Temp:=Int_Acc(i);
j:=2*i;
if Temp>Int_Acc(j) then
elsif Temp<=Int_Acc(j) then
Int_Acc(j/2):=Int_Acc(j);
j:=2*j;
end if;
end loop;
Int_Acc(j/2):=Temp;
end Max_Heapify;
begin
Get(n);
for i in MyArr'range loop
Put_Line("Enter Element " & Integer'Image(i));
Get(MyArr(i));
end loop;
end;
end sort;
Thanks in advance :)
Your Problem is that you are insisting on writing Ada code using c - Style programming paradigms.
Firstly:
The declarations:
Type Arr is array(1..20) of Integer;
Type int_access is access Arr;
MyArr : int_access;
Where you use Int_Acc : in out int_access as parameters to procedures are useless in Ada. You are trying to pass a pointer to an array in (which you are doing!), but you should just pass your Type Arr as in out - The Ada compiler knows to do this as a pointer!
Secondly:
I cannot see where you actually allocate any memory to MyArr. This is a possible source of your runtime error. (when you write to or index an array that does not exist, i would expect to have a problem!)
Thirdly:
You seem to be mixing fixed length arrays with variable length input. If N > 20, you will have a problem.
Fourthly:
Insulting the language is not the best way of getting help from those who like it.
NWS has nailed it : there is a pointer, but no array there.
But it's clear that you have learned C, which leaves you with a lot to learn about other languages including Ada. There really are better ways of doing many things, that aren't taught to C programmers because C doesn't allow them.
Allocating variable sized arrays without pointers, malloc and free for example...
Type Arr is array(positive range <>) of Integer; -- of any size
begin
Put_Line("Enter Number Of Elements Of Array");
Get(n);
declare -- now we know the size
My_Arr : Arr(1 .. n);
begin -- My_Arr is in scope until the end of this block
...
end;
end sort;
Using the type system better...
Bad programming :
for i in 1 .. n loop
Get(MyArr(i));
end loop;
HeapSort(MyArr,n);
for i in 1 .. n loop
Put_Line(Integer'Image(MyArr(i)));
end loop;
This is bad because it violates the DRY principle : loop bounds repeated, and something that hopefully represents the array size passed around as a separate parameter... a maintenance nightmare if you decide to rename n to something meaningful for example.
better programming : Use the type system. Recognise that merely declaring an array has declared a new subtype of integer, representing the index of the array. You can access it as My_Arr'range, and the high bound as My_Arr'last.
for i in My_Arr'range loop
Get(MyArr(i));
end loop;
HeapSort(MyArr);
for i in My_Arr'range loop
Put_Line(Integer'Image(MyArr(i)));
end loop;
And accidents such as redefining n after the array declaration can no longer generate buffer overflows.
NOTE: Heapsort now gets its range from the array. (Max_Heapify may still need a separate parameter to operate on subsets of the array)
Arguably best - if it makes the intent clearer - name the index datatype explicitly and use it...
declare -- now we know the size
subtype My_Range is positive range 1 .. n;
My_Arr : Arr(My_Range);
begin -- My_Arr is in scope until the end of this block
for i in My_Range loop ...
And lastly, which do you prefer; a Storage_Error exception immediately the bug occurs (writing to memory you forgot to allocate) or something odd happening much later because something scribbled across another variable?
EDIT
Having cleared up the major issues two more subtle ones remain...
If I compile the modified program (in Gnat 4.8) I get several warnings : one of them is important and tells you exactly what the problem is...
Most of the warnings stem from the fact that
for i in My_Arr'range loop
declares its own loop variable i which hides any existing in-scope declaration. So you can tidy up the code by removing the unnecessary declarations.
What remains is:
sort.adb:51:28: warning: loop range may be null
sort.adb:51:28: warning: bounds may be wrong way round
The for loop bounds are empty ranges, reversed...
1 .. 3 declares a subtype with 3 values
reverse 1 .. 3 declares the same subtype and iterates backwards over it.
But 3 .. 1 declares an EMPTY subtype (containing NO valid values) so iterating over it - either way round - does precisely nothing.
Hopefully that is the missing part of the puzzle. I'm not clear why one faulty loop gets this warning while the other (at line 38) doesn't...
if j<n **and then** Int_Acc(j+1)>Int_Acc(j) then
j:=j+1;
I think you want just 'and' instead of 'and then,' although I haven't looked at Ada code in years.
Did that compile?

Resources