Forcing Ada to use minimum spec size for enumerated types with gnat 4.4 - size

I have an enumerated type that needs to be 4 bits but when I declare a variable of that type the compiler assigns that variable 8 bits.
Below is a simplified version of the code.
subtype ab_range_index is word range 0..3;
type ab_buffer_type is array(ab_range_index) of bit;
type Buffer is record
...
var1 : some_buffer_type;
Orig_AB_var : ab_buffer_type;
...
end record;
for Buffer use record
...
var1 at 16 range 0..5;
Orig_AB_var at 16 range 6..9;
...
end record;
...
type AB_type is (A,B);
for AB_type use (A => 0, B => 5);
for AB_type'Size use 4;
...
procedure Proc(AB_buff : ab_buffer_type) is
AB_var : AB_type; -- AB_var'Size returns 8 in debugger.
for AB_var use at AB_buff'Address;
begin
data_valid = AB_var'valid; -- returns false since the variable
-- contains extra bits
...
This all worked under previous gnat versions but not under gnat 4.4.6. I understand that gnat is in compliance with the Ada spec.
Is there a way to force the compiler to make the AB_var in the above example to be 4 bits?
I've tried 'Object_Size but it needs to be a multiple of 8 bits.

I don't know of any modern computer hardware that can allocate just 4 bits for a variable. The minimum would be an 8-bit byte.
And no offense, but I'm skeptical that any previous version of GNAT would have been able to do it either.
Now within a record that has an associated rep spec or suitable convention pragma, an individual field of type AB_Type could be allocated just 4 bits.
But not as a discrete variable.

Add Pragma Pack( [type_name] ); to the types, especially to the record. I recently had a case where even a record-specification clause would not work unless pack was attached to the type. (The aspect form can be used as well.)

There's almost always something to be said for posting a compilable reproducer. I'm not sure what your code is really like, but this works just fine with GCC 4.8.0:
with Ada.Text_IO; use Ada.Text_IO;
procedure Small_Parameter_Conversion is
type M_N_Type is (M, N);
for M_N_Type use (M => 0, N => 5);
for M_N_Type'Size use 4;
type Fill is array (Positive range <>) of Boolean;
for Fill'Component_Size use 1;
type Import is record
M_N : M_N_Type;
Filler : Fill (1 .. 4);
end record;
for Import use record
M_N at 0 range 0 .. 3;
Filler at 0 range 4 .. 7;
end record;
type A_B_Type is (A, B);
for A_B_Type use (A => 0, B => 5);
for A_B_Type'Size use 4;
procedure Proc (Input : M_N_Type) is
A_B : A_B_Type;
for A_B'Address use Input'Address;
begin
if not A_B'Valid then
Put_Line ("invalid.");
else
Put_Line (A_B'Img);
end if;
end Proc;
V : Import;
begin
V := (M_N => M, Filler => (others => True));
Proc (V.M_N);
V := (M_N => N, Filler => (others => True));
Proc (V.M_N);
end Small_Parameter_Conversion;
That said, Unchecked_Conversion is the better way to go. The last paragraph but two of the GNAT Reference Manual section on Address Clauses points out that using overlays is implementation-dependent (though I couldn't find where it says this in the RM).
One possible route to error would be if M_N_Type was in fact defined as
type M_N_Type is (M, N, O);
for M_N_Type use (M => 0, N => 5, O => 6);
and Proc is called as
V := (M_N => O, Filler => (others => True));
Proc (V.M_N);
Then, sure enough, it prints invalid..

Related

Maple Sequence Length

I'm trying to create a basic program in Maple that runs the Collatz sequence when given a number (n) from the user. For those that don't know, the Collatz sequence is basically "If the number given is odd, do 3n + 1, if it is even, divide by 2 and continue to do so for every answer. Eventually, the answer will reach 1"
I'm trying to grab the number of iterations that the sequence is performed, say if the sequence is run through 10 times, it prints that out. Here is my current code:
Collatz := proc (n::posint)
if type(n, even) then (1/2)*n
else 3*n+1
end if
end proc
CollSeq := proc (n::posint)
local i;
i := n;
while 1 < i do
lprint(i);
i := Collatz(i)
end do
end proc
This so far works, and if the proc CollSeq(50) is entered, it will perform the Collatz sequence on 50 until it reaches 1. The bit I am stuck on is the length of the sequence. I have read around and learned that I might be able to use the nops([]) function of Maple to get the length of the sequence. Here is what I have tried:
CollLen := proc (n::posint)
local c;
c := CollSeq(n);
print(nops([c]))
end proc
I have a feeling this is horribly wrong. Any help would be much appreciated.
Many Thanks
Your function fails to return the actual sequence of values. You need to accumulate it as you go through the loop.
CollSeq := proc (n::posint)
local i, s;
i := n;
s := i;
while 1 < i do
lprint(i);
i := Collatz(i);
s := s, i;
end do;
s;
end proc
The lprint() command just prints its argument to the terminal (showing it on screen), it DOES not save it in a list. And nops() or a better command numelems() counts the number of elements in a list! So putting nops around something that has lprint will not count the number of things. Instead of using lprint in your second function (procedure), define a list, or better than list, an array and in the lprint-line, use a command to append the new number to your growing collection. If you want to see these numbers, just print this collection. Now this time, your third function can have a meaning and it will work as you expected.
Here is the closest fix to your codes.
Collatz := proc( n :: posint )
if type(n, even) then
return( n/2 ):
else
return( 3*n+1 ):
end if:
end proc:
CollSeq := proc ( n :: posint )
local
i :: posint,
c :: 'Array'( posint ):
i := n:
c := Array([]):
while 1 < i do
ArrayTools:-Append( c, i ):
i := Collatz( i ):
end do:
return( c ):
end proc:
CollLen := proc ( n :: posint )
local c :: posint:
c := CollSeq( n ):
return( numelems( c ) ):
end proc:
Here is a screenshot of using them in a Maple worksheet.
Why do I use an array and not a list? Because if you use a list which is immutable, each time you want to add an element to it, in fact it is defining a new list. It is not a memory efficient way, while array is mutable and your edits modifies the array itself. See the help pages on these in Maple.
And looking at your codes, it seems you have the same problem that some of my students in their first programming course usually have, return and print are not the same thing. If you really want a "print" action, that is fine, but you should not expect that the printed value be the output of the function unless you are using a return line inside the function that returns the same value of the print as well. For example you can have print(c): before return(c): in the second function above. So it both prints the sequence on the terminal and returns it to be used by another function or line of code.

Ada types size difference

I have this Ada program:
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;
procedure test is
type MY_TYPE is new Integer range 1..20;
subtype MY_TYPE2 is MY_TYPE range 5..6;
c : MY_TYPE:=10;
f : MY_TYPE2 :=6;
begin
put(Integer(c'SIZE));
end test;
and when I run it I get 32. If I replace
type MY_TYPE is new Integer range 1..20;
with
type MY_TYPE is range 1..20;
I get 8. What is the difference between the two declarations?
This:
type MY_TYPE is new Integer range 1..20;
explicitly inherits MY_TYPE from Integer, which apparently is 32 bits on your system.
This:
type MY_TYPE is range 1..20;
leaves it up to the compiler to decide what to inherit MY_TYPE from how to represent MY_TYPE. The result is implementation-specific; apparently your compiler chooses to implement it as an 8-bit integer type.
You are allowing the compiler to choose the sizes for these different type declarations, and it is picking the size of your INTEGER type according to the size of its base type (INTEGER).
You have control over the sizes of these types : if you rewrite the first declaration as
type MY_TYPE is new Integer range 1..20;
for MYTYPE'SIZE use 8;
you should get an 8-bit MY_TYPE.
for MYTYPE'SIZE use 5;
ought to pack MYTYPE into 5 bits (as I understand it, a compiler is permitted to reject this with an explicit error, or generate correct code, but NOT to accept it and generate garbage.)
Why would you want to pack MYTYPE into 5 bits? One reason is if it's used as a component of a record : that leaves room for 3 more components in a single byte, as long as they are booleans and their SIZE attribute is 1!
This may look like extreme packing, but it's actually quite common in embedded programming, where that record type matches the bits in a peripheral or I/O port. You would also specify the bit-level layout within the record, as in:
type Prescale is new Integer range 1..20;
for Prescale'SIZE use 5;
type Timer_Ctrl_Reg is record
Scale : Prescale;
Up : Boolean;
Repeat : Boolean;
Int_En : Boolean;
end record;
for Timer_Ctrl_Reg use record
Scale at 0 range 0 .. 4;
Up at 0 range 5 .. 5;
Repeat at 0 range 6 .. 6;
Int_En at 0 range 7 .. 7;
end record;
at specifies the offset from the record base in "storage units" usually bytes or words : range specifies the bit positions within the storage unit.
No more dodgy bit masking and extraction to worry about!
On the other hand,
for MYTYPE'SIZE use 4;
ought to fail, as MYTYPE has more than 16 discrete values.

Is it possible to declare variables in VHDL with an asterisk?

Quite new to VHDL here, so I'm not entirely sure if this is feasible at all, but here goes:
In my test code for some RAM, I have 2 8-bit std_logic_vector variables wdata_a_v and wdata_b_v. This is all I need for the current setup, but if the ratio of read to write data length changes, I will need more variables of the name wdata_*_v. I'm trying to write the code generically so that it will function for any amount of these variables, but I don't want to declare 26 of them in the code when I will likely only need a few.
It would be nice if there was a way to declare a variable like so:
variable wdata_*_v : std_logic_vector (7 downto 0);
that would, behind the scenes, declare all of the variables that fit this framework so that I could write a loop without worrying about running out of variables.
If there's a way to write a function or procedure etc. to make this work, that would be excellent.
Yes, you can go with a 2d array, recipe:
entity TestHelper is
generic (n: natural range 2 to 255 := 8);
end TestHelper;
architecture behavioral of TestHelper is
type array2d is array (n-1 downto 0) of std_logic_vector(7 downto 0);
begin
process
variable a : array2d;
begin
a(0)(0) := '0';
end process;
end architecture behavioral;
EDIT: Now to use it and create similar code for each of wdata_*_v:
process
variable wdata_v : array2d;
begin
someLabel: for i in 0 to n-1 generate
wdata_v(i)(0) := '0';
x <= y and z;
...
end generate;
x <= '1';
...
anotherLabel: for i in 1 to n generate
...
end generate;
...
end process;

VHDL shift operators?

I'm still trying to get used to some of the quirks of VHDL and I'm having a bit of an issue. First off, I understand that shift operators like rol, ror, ssl, srl, etc. are not synthesizeable. The purpose of this lab is to use a golden model to check against a synthesizeable version of the same thing in a testbench.
Now, the purpose of this program is to convert thermometer code into a 3-bit binary number. So, in other words, thermometer code "00000001" = "001", "00000011" = "010", "00000111" = "011", etc. I'm basically trying to count the number of 1's in the string from right to left. There will be no case where a '0' is placed between the string of 1's, so the vector "00011101" is invalid and will never occur.
I've devised a non-synthesizeable (and so far, non-compile-able) algorithm that I can't figure out how to get working. Basically, the idea is to read the thermometer code, shift it right and increment a counter until the thermometer code equals zero, and then assign the counter value to the 3-bit std_logic_vector. Below is the code I've done so-far.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity therm2bin_g is
port(therm : inout std_logic_vector(6 downto 0); -- thermometer code
bin : out std_logic_vector(2 downto 0); -- binary code
i : integer range 0 to 7);
end therm2bin_g;
architecture behavioral_g of therm2bin_g is
begin
golden : process(therm)
begin
while(therm /= "00000000") loop
therm <= therm srl 1;
i = i + 1;
end loop;
bin <= std_logic'(to_unsigned(i,3));
end process golden;
behavioral_g;
here's a version that is synthesisable. the while loop is replaced by a for loop. srl is implemented explicitly:
entity therm2bin_g is
port(therm : inout std_logic_vector(6 downto 0); -- thermometer code
bin : out std_logic_vector(2 downto 0); -- binary code
i : out integer range 0 to 7);
end therm2bin_g;
architecture behavioral_g of therm2bin_g is
begin
golden : process(therm)
variable i_internal: integer range 0 to 7;
begin
i_internal:=0;
for idx in 0 to therm'length loop
if therm/="0000000" then
therm<='0' & therm(therm'left downto 1);
i_internal := i_internal + 1;
end if;
end loop;
bin<=std_logic_vector(to_unsigned(i_internal,bin'length));
i<=i_internal;
end process golden;
end behavioral_g;
"... operators like rol, ror, ssl, srl, etc. are not synthesizeable..."
Who says that on who's authority? Have you checked? On which synthesis tool? Was it a recent version, or a version from the early 1990s?
Note that the argument that some tools might not support it is just silly. The fact that some kitchens might not have an oven does not stop people from writing recipes for cake.

How to multiply matrix with its transpose using Oracle database and utl_nla

I'm going nuts with this issue. I can't get the result from the following multiplication:
X^t * X
X is an m * n matrix with m = 36 rows and n = 3 columns which is represented by an utl_nla_array_dbl datatype. The data origins from a table and gets copied by simple pl/sql code.
To solve my problem, I chose the method utl_nla.blas_gemm. It's a matrix-matrix method, in contrast to utl_nla.blas_gemv as a matrix-vector method (I got that one working. I was able to multiply that very matrix X by a vector y and received the right result).
Here is the relevant code, which outputs me a matrix with the right dimension (3X3) but just zeros in it. To make it clearer I hard coded most parameters:
utl_nla.blas_gemm(
transa => 'T',
transb => 'N',
m => 3,
n => 3,
k => 36,
alpha => 1.0,
a => X,
lda => 3,
b => X,
ldb => 3,
beta => 0.0,
c => XtX,
ldc => 3);
The variable XtX is also of type utl_nla_array_dbl and is to hold the result.
Any idea what I'm doing wrong? I'll appreciate every contribution since I'm totally stuck and can't find any help elsewhere on the web.
I had the same problem, and after a few days I'm sure , that the UTL_NLA.BLAS_GEMM procedure is broken.
It was broken in the 10.2g version, and still the same error occurs in version 11.2g.
The problem is in the in wrapper procedure written in PL/SQL.
It does not handle the parameters
M, N, K, LDA, LDB, LDC correctly,
in the case when one or both of the parameters TRANSA, TRANSB are set to 'T'.
Not surprisingly it is working, when the matrix is a sqare matrix,
for example the matrix A is 100x100 and the relevant parameter TRANSA = 'T'.
The procedure UTL_NLS.BLAS_GEMM mishandles the parameters in this case too,
but they are equal, so it has no effect.
The workaround I use is simple: before I call the procedure, I transpose the relevant matrix,
and I use BLAS_GEMM allways with the setting TRANSA = 'N' and TRANSB = 'N'.
Unfortunately there is no transpose procedure in the UTL_NLA package (btw. BLAS has one),
but to write one is not a big deal:
PROCEDURE MatTranspose (nRows IN NUMBER, /* number of rows in A */
nCols IN NUMBER, /* number of columns in A */
mat_A IN utl_nla_array_dbl, /* supposed it is stored column-wise i.e. 'C' */
mat_At IN OUT utl_nla_array_dbl) IS
/* the array can be larger then nRow * nCol, the rest part is not handled in either matrices */
nIii NUMBER;
nJjj NUMBER;
BEGIN
FOR nIii IN 1 .. nRows LOOP
FOR nJjj IN 1 .. nCols LOOP
mat_At (nJjj + nCols * (nIii - 1)) := mat_A (nIii + nRows * (nJjj - 1));
END LOOP;
END LOOP;
END MatTranspose;
For me the real pain was the documentation, e.g. e40758.pdf.
It is full of mistakes too, see for instance p. 232-26 and it misleads me, makes me think I pass the wrong parameters.
I spent couple of hours searching the web for a working example but - of course - in vain.
It is probably a simple error in the BLAS_GEMM procedure which takes half an our to fix,
and yet developers are waiting more then 6 years for a correct version.
After looking at the spec for UTL_NLA and reading the description of BLAS_GEMM, it looks to me like LDA and LDB should be 36. Try changing those and see if it helps.
Share and enjoy.