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?
Related
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.
I am a newbie in verilog. I have been searching online and most of them suggest to not use for-loop in verilog coding. So is there a better alternative to replace for-loop?
The problem that I am facing now is that I need to perform 1 or 2 for-loop in a case statement. And I have been thinking of better alternatives but come up with none. It will be great if any one of you can shed some light on this.
Example of my code:
always #(*)
case (help)
4'd1: for (i=A; i<=20;i=i+B)
begin temp[i-1]=1; end
4'd2: for (i=A; i<=20;i=i+B)
begin temp[i-1]=1; B=B+1; end
4'd3: begin
for (i=A; i<=20;i=i+B)
begin temp[i-1]=1; B=B+1; end
for (i=A; i>=1;i=i-B)
begin temp[i-1]=1; B=B+1; end
end
default: temp = 0;
For-loops are fine in Verilog, but they need to able to static unroll if you plan on synthesizing. Static unroll means the loop is not depended on any external variables. For example for(i=0;i<10;i=i+1) is static. for(i=A; i<=20;i=i+B) is not static as it is a depends on the variables A and B.
You can make a loop static my moving the variables as a condition inside the for-loop. for(i=A; i<=20;i=i+B) becomes:
tmp_var = A;
for (i=0; i<=20;i=i+1) begin
if (i==tmp_var) begin
// ... your logic here ...
tmp_var = tmp_var+B;
end
end
Issues that need to be addressed beyond the scope of the question:
They way you are using B and temp is a little concerning.
B appears to be an input, but you are also incrementing it. For synthesis it is illegal to manipulate an input. If it is an input, then create a local variable with default value as B and you may change this value later in the within same always block. If it is not an input, then it is creating latching logic; which is not good and I will cover that next with temp.
temp is latching logic. Latching logic are troublesome because timing is critical; knowing when the latch is transparent or closed, and respecting the hold time requirements. The more complex the logic the harder it is to predict. In RTL one way latches are inferred is by incomplete assignments inside an combinational blocks (ie always #*). To resolve this, make sure every bit is assigned each pass of the combinational blocks. One way to safe guard this is to assign default values before staring your logic. Example:
always #(*) begin
temp = 0; // default to a constant
temp_B = B; // default to an input value
// ... your logic ...
end
Functions are obviously less verbose to write than entities. But it implies many drawbacks, including:
No generic keyword equivalent
Only one output possible
It appears that functions can be called recursively. May it not be the case with entities? If so, is there any good reason to use functions except for aesthetic purposes?
Functions can't create hardware directly - they have to exist within an architecture to do so. There's nothing to stop you putting all your functionality into a function (or procedure) and then just calling that within a process though.
Regarding some of your other points:
With procedures you can have multiple inout or out parameters.
Entities can recurse... Consider:
entity recurse is
generic (
depth : integer := 1;
param : integer := 3);
port (
a : in integer;
b : out integer);
end entity recurse;
architecture a1 of recurse is
signal c : integer;
begin
c <= a + 1;
bottom: if depth = param generate
b <= a + 1;
end generate bottom;
mid:if depth /= param generate
recurse_1: entity work.recurse
generic map (
param => param,
depth => depth+1)
port map (
a => c,
b => b);
end generate mid;
end architecture a1;
Not very useful, but it synthesises and simulates just fine.
And finally, of course you only use functions for aesthetic purposes (assuming you include maintainability and readability into the definition of aesthetic, which most programming types do in my experience). You only use enumerated types, entities, records and a whole host of other language features for 'aesthetic purposes'. Even assembly mnemonics are aesthetic! Maybe should return to toggling DIP switches :)
Functions in vhdl make the code easy to maintain and read. generally architectures are very big and while debugging if something is not working you can easily find the problematic function and correct it and no need to analyse the entire architecture body.
in case of small codes it's useless but in more big machines it makes you better understand if you consider it function wise.
There is no rule for this so all comments are welcome.
in short : the advantage of functions are
overloading
operators definition
overloading of operators therefore
Better Structure of code
I can see why you are confused, another good question would be why there's both procedure and function. (VHDL seems quite inelegant sometimes!)
That being said, I use both procedures and functions all the time, although mostly in testbenches. For example, for a testbench for a firewall system I made a while back I wrote a procedure called pd_tb_send_udp_packet() that I use repeatedly in the main process, e.g.,
pd_tb_send_udp_packet("10.10.10.2", 1234, false);
pd_tb_send_udp_packet("10.10.10.1", 1234, true);
pd_tb_send_udp_packet("10.10.10.1", 1235, false);
pd_tb_send_udp_packet("ff02:100::1", 1234, false);
pd_tb_send_udp_packet("ff02:101::1", 1234, true);
This procedure generates a random UDP packet with the given addr/port and sends it to the firewall system, then tests whether it is forwarded or not based on the final boolean parameter. Here are the first lines of it, where I use functions from a library:
if f_atvtb_is_ipv6_addr(dest_ip_addr) then
v_ipv6 := true;
v_ipv6_addr := f_atvtb_ipv6_addr(dest_ip_addr);
else
v_ipv6 := false;
v_ipv4_addr := f_atvtb_ip_addr(dest_ip_addr);
end if;
The latter two return 128 and 32 bit std_logic_vectors from the string input, respectively.
While I could probably do all this without using procedures and functions somehow, it would definitely be a lot more messy.
I'm having a problem when I use these 2 FOR to initialize a two dimensional vector/array:
I have these types defined:
type
Range9 = 0..8;
Digit = '0'..'9';
Board = array [Range9,Range9] of Digit;
and then the part of the code where there are problems with the FOR's is the following:
var
i : Range9;
j : Range9;
table : Board;
BEGIN
for i:=0 to 8 do begin
for j:=0 to 8 do begin
table[i,j] := '0'
end
end;
END.
Now the problem is that, when I debug this portion of code, for some reason, my i variable is modified when it's not supposed to.
For example, I have a watch on i and j and if I put a breakpoint in the line table[i,j] := 0
I see with the watches these values:
i j
0 0
256 1
512 2
768 3
1024 4
1280 5
1536 6
1792 7
2048 8
2049 8
1 0
257 1
513 2
769 3
and so on...
So, when the program enters in the second for (the one that increases the j) my i increases in intervals of 256... I really don't know why is this happening.
And another thing I discovered is that, the problem solves if I change the TYPE of the i variable.
If in the VAR section I put i : integer instead of i : Range9, i doesn't get modified when isn't supposed to.
I would really appreciate if someone explains me why is happening this.
I've found the answer to my own question... well, I didn't exactly found the answer, I've asked this same question in the forum board of the programming course I'm attending and one of the professors gave me this link:
(it's in spanish btw)
http://www.fing.edu.uy/inco/cursos/prog1/pm/field.php/FAQ/Laboratorio#toc17
A quick translation:
This happens with variables defined as subranges. The reason isn't sure; but without doubt is an implementation error of the debugger. There is a 'trick' that can work to solve this (although not always), to be able to see the correct values on the debugger:
Suppose that you have the following variable in your program:
var anything: 1 .. 10;
Add in your program a integer variable which won't be used in any part of the program:
var anything: 1..10;
aux: integer; { only for the debugger }
Then when you define the debugger watch, instead of adding the anything variable, you should add the following expression:
aux:= anything
The aux variable can be used to view different variables, so you only need to declare one aux variable.
In some cases, the previous may not work. Another solution is to change the type of all the variables defined with subranges to integer, char, string, etc (depending the case) only for debug and the change it back again.
end of the translation.
Hope this will be useful for someone else facing the same error.
BTW, this happens with the debugger of free pascal IDE 2.2.2 , maybe in another IDE/compiler/debugger of pascal it doesn't happen.
I haven't done Pascal in a while, so I might be a bit rusty. The only thing I can think of that is creating your problem is that you created a character range that was interpreted as a byte array, which was then converted to a Digits and then multiplied, which gave you those weird values. But, I could be wrong. I am unfamiliar with FreePascal.
Type
Range9 = 0..8
Board = Array[Range9,Range9] of Integer;
var
A : Board;
I,J : Integer;
begin
For I:=0 to 8 do
For J:=0 to 8 do
A[I,J]:=I*J;
end.
Reference: ftp://ftp.freepascal.org/pub/fpc/docs-pdf/ref.pdf
This snippet not only causes a runtime error, it makes FPC close if I run it using the debugger.
procedure sortplayersbyscore(var vAux:tplayers);
procedure swap(var a:trplayers;var b:trplayers);
var
rAux:trplayers;
begin
rAux:=a;
a:=b;
b:=rAux;
end;
var
i,j:integer;
sorted:boolean;
begin
vAux:=playersarray;
i:=1;
sorted:=false;
while (i <= MAXPLAYERS -1) and not sorted do
begin
j:=1;
sorted:=true;
while (j <= MAXPLAYERS -i) do
begin
if (vAux[j].score < vAux[j+1].score) then
begin
swap(vAux[j],vAux[j+1]);
sorted:=false;
end;
inc(j);
end;
inc(i);
end;
end;
The code itself is part of a really big source file, I can post the whole thing but the responsible for the error is just that bunch of lines. The debugger terminates at line:
swap(vAux[j],vAux[j+1]);
tplayers is just a type defined as an array of records that contain score (an integer) among a bunch of other variables. trplayers is the type of the aforementioned records. I'm at a total loss; FPC (while not under debugging mode) spits an out-of-range error but under my watches I see that the variables I'm trying to read exist. Any help is really appreciated!
rAux:trplayers; have you typed a wrong symbol or the type here really contains "r" in its name?
It looks valid (other than typos) ... so let's try something simple.
What's the value of "j" when you abort?
If the debugger won't tell you, try adding:
writeln ('j = ', j);
just before the "swap" call.
As Yochai's question implied, your array needs to be dimensioned at least from
1 (or lower) to MAXPLAYERS (or larger). (I.e.: 0..MAXPLAYERS-1 would not work,
but 1..MAXPLAYERS should.)