Compare Enum Values - enums

I want to loop over an array and check, whether the current array index is a value of an enumeration. The array as well as the enumeration are defined as the following:
type Option is (None, A, B, C, D);
type Votes is array(Option) of Natural;
Zero_Option_Distribution: constant Votes := (others => 0);
Votes_Distribution: Votes := Zero_Option_Distribution;
The Loop looks like this:
for I in Voting_System.Votes_Distribution'Range loop
-- this is where I would like to check whether I is a representation of either of the enum values
end loop;
I already tried everything that came to my mind, like
if I = Voting_System.Option(None) then -- ...
and
if I'Val("None") then -- ...
and some more versions where each of them didn't work.
I really don't have any more ideas to achieve this.

You compare values of objects of enumeration types just like objects of any other type, using =:
if I = None then
...
end if;

-- this is where I would like to check whether I is a representation of either of the enum values
Based on this line in your question, I assume Party is an Integer subtype or something? You should be able to just use something like this:
-- (Checks if I is 0)
if (Integer(I) = Voting_System.Option'Pos(Voting_System.Option.None)) then
-- ...

If Party is a distinct type, in accordance with ARM95 3.5.1 §7 and ARM95 Annex K §175 you may try something like this:
for I in Votes_Distribution'Range loop
case Party'Pos (I) is
when Option'Pos (None) => Put_Line (I'Img & " is for «None»");
when Option'Pos (A) => Put_Line (I'Img & " is for «A»");
when Option'Pos (B) => Put_Line (I'Img & " is for «B»");
when Option'Pos (C) => Put_Line (I'Img & " is for «C»");
when Option'Pos (D) => Put_Line (I'Img & " is for «D»");
when others => Put_Line ("I not in Option");
end case;
end loop;
Need others in all cases because we moved to work with type Universal_Integer.

Related

Use Others with Aggregate in VHDL

I'm trying to return a word which is defined as:
subtype word is std_logic_vector(word_len - 1 downto 0);
By concatenating a whole bunch of other inputs from a record like so (this is inside a switch block):
return get_opc(ins.op) & std_logic_vector(ins.val) & "0000"; -- TODO Replace these with some sort of others construct
However, different opcodes have different sets of other inputs and so the amount that needs to be right-filled with zeroes changes. I'm not a huge fan of manually hardcoding trailing zeroes, it's a mess ad it won't play well if I resize my word.
My instinct was to try:
return get_opc(ins.op) & std_logic_vector(ins.val) & (others => '0');
But apparently you can't use others as an aggregate in this context.
I know I could create a buffer the size of a word, fill it with zeroes and then slot my different inputs into different slices but AFAIK, that would be extremely verbose, requiring me to specify the start and end point of each slice rather than just concatenating them on the left. This would soon get very messy.
Is there any easy way around this that keeps everything concise?
If you use VHDL-2008 (or VHDL-2019!), you can return an aggregate like this:
return (get_opc(ins.op), std_logic_vector(ins.val), others => '0');
This assumes that your return type is constrained. In other words, this is OK:
function F return word is
begin
return (get_opc(ins.op), std_logic_vector(ins.val), others => '0');
end function;
whereas if your return type is unconstrained like this, then it is not OK:
function F return std_logic_vector is

VHDL way to group constants together

Is it possible to group related constants together inside of packages?
What I want to do is to have generic constants but then grouped together with related constants and types. In software like Python this could be done with package inside of package or class to group constants together.
What I want to do is something like this:
library constants;
...
if (some_signal = constants.group_a.SOME_CONSTANT_VALUE) then
...
end if;
Reader can see where the constant is coming from like here group_a.
If I understand the question well you can use records inside your package
package ex_pkg is
type constants_group_1_t is record
CONSTANT1 : integer;
CONSTANT2 : integer;
CONSTANT3 : integer;
CONSTANT4 : integer;
end record constants_group_1_t;
constant constant_group1 : constants_group_1_t := (
CONSTANT1 => 1,
CONSTANT2 => 2,
CONSTANT3 => 3,
CONSTANT4 => 4
);
end package;
then you can use it as
liberary work;
...
if some_integer = work.ex_pkg.constants_group1.CONSTANT1 then
end if;
so basically you declare a new record type containing all the constants that you want to use, which can be any of your chosen types, then creating a constant of the newly created type and assign for each field its value. You can then access it like "record.field" moreover you can define a record of records for as deep abstraction as you want.

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);`

Generate a table with random elements

I am new with Ada programming. I am trying to generate a 80 column and 40 rows table, each case is randomly filled with either M or V. Any help with how to create this kind of table would be much appreciated !
Here's what I have so far for the table in .ads :
package Life is
type Grid is (mort, vivant);
type TableauCell is array ( 0..80, 0..40 ) of Grid;
procedure Grid_Random_Fill(A : in out Grid);
end Life;
and the randomization:
with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Numerics.Discrete_Random ;
use Ada.Text_IO, Ada.Integer_Text_IO;
package body Life is
procedure Grid_Random_Fill is
type Life is (V, M);
package Random_Life is new Ada.Numerics.Discrete_Random (Life) ;
use Random_Life ;
G : Generator ;
begin
Reset (G) ; -- intialise the generator
loop
Case Random(G) is
when V =>
put("V"); -- put V in table
when M =>
put("M"); -- put M in table
end case;
end loop ;
end Grid_Random_Fill;
end life;
Unfortunately I can't get it to compile - and I don't see how I can automatically generate M and V into my table. I'm not sure I was clear, I'm all new to coding.
This sounds homeworkish, so this is going to be kept somewhat abstract.
Declare a two-element type to represent M and V.
Declare an 80x40 array of that type.
Instantiate Ada.Numerics.Discrete_Random with that type.
Iterate over the array bounds, setting each array element via a call to the random number package's Random() function.
Since this has the feel of homework, how about an overly-complex, overly-generalized example?
Everything works, except the randomization, which is an exercise left to the reader.
Test_Table.adb
With
Tabling,
Ada.Streams.Stream_IO,
Ada.Text_IO.Text_Streams;
Use
Ada.Text_IO;
Procedure Test_Table is
-- Here we declare a stream and associate it with the standard-output,
-- this can easily be altered to any file. Yay streams!
Output : Access Ada.Streams.Root_Stream_Type:=
Ada.Text_IO.Text_Streams.Stream( Standard_Output );
Package test is new Tabling( Rows => 40, Cols => 80 );
temp : test.Table;
Begin
-- A single line to write the table.
Test.Table'Write( Output, temp );
New_Line;
End Test_Tables;
Now isn't that nice and simple? Well, here's the over-complex & over-generalized part: the specification and implementation!
Tabling.ads
Pragma Ada_2012;
With Ada.Streams;
Generic
Rows : Positive := 3;
Cols : Positive := 4;
Package Tabling is
-- Tables with rows or columns exceeding 200 are absurd, so we disallow them.
Maximum : constant:= 200;
Pragma Assert (Rows <= Maximum and Cols <= Maximum);
-- Table is a private entity.
Type Table is private;
-- Forward declaring the rows and columns here.
Type Col is private;
Type Row is private;
Private
Use Ada.Streams;
-- We are defining a type with elements of 'V' or 'M'.
Type Element_Type is ( 'M', 'V' );
-- We are declaring a stream writing function.
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Element_Type);
-- We are overriding the default write function with the one we defined.
For Element_Type'Write use Write;
-- Because we don't want an allocation wrror we restrict index-ranges to
-- a more reasonable value.
SubType Short_Positive is Positive Range Positive'First..Maximum;
-- We create subtypes representing the ranges that Rows or Columns take.
subtype column_index is Short_Positive Range Positive'First..Cols;
subtype row_index is Short_Positive Range Positive'First..Rows;
-- Here we define stream-writing functions for rows and columns.
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Col);
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Row);
-- Here we override the stream-writing methods for rows and columns.
For Col'Write Use Write;
For Row'Write Use Write;
-- Here we finally define Rows and Columns.
Type Col is Array(column_index)of Element_Type;
Type Row is Array( row_index ) of Col;
-- THIS IS A STUB, SUBSTITUTED FOR YOUR CALL TO RANDOM.
Function RANDOM_CALL Return Element_Type is ( 'M' );
-- Finally we define the stream-writing for a table...
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Table);
-- and define what a table is...
Type Table is record
Data : Row:= ( others => (others => RANDOM_CALL) );
end record;
-- finishing off by assigning our write function to the type.
For Table'Write Use Write;
End Tabling;
Tabling.adb
package body Tabling is
-- Quick definition of the new-line, windows-style.
New_Line : Constant String:= ASCII.CR & ASCII.LF;
-- Implementations of our stream writing functions.
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Element_Type) is
-- Convert takes the element-type and transforms it into a character.
Function Convert (Input : Element_Type:= Item) Return Character is
begin
-- A simple mapping using case, it also has the advantage of raising
-- a compiler error should the valuse "Element_Type" can take change.
case Input is
when 'M' => return 'm';
when 'V' => return 'v';
end case;
end Convert;
begin
Character'Write( Stream, Convert );
end Write;
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Col) is
begin
-- Using the new-style for-loop, we iterate over the given columns,
-- taking care to wrap the elements in the table's cell-definition tag.
for Element of Item loop
String'Write( Stream, ASCII.HT & "<td>" );
Element_Type'Write( Stream, Element );
String'Write( Stream, "</td>" & New_Line );
end loop;
end Write;
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Row) is
begin
-- Using the new-style loop, we iterate through the row, wrapping each
-- in the table-row tag, <tr>.
for Element of Item loop
String'Write( Stream, "<tr>" & New_Line);
col'Write( Stream, Element );
String'Write( Stream, "</tr>" & New_Line);
end loop;
end Write;
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Table) is
begin
-- Start the table.
String'Write(Stream, "<Table>" & New_Line);
-- Write out the rows.
Row'Write (Stream, Item.Data );
-- End the table.
String'Write(Stream, "</Table>");
end Write;
End Tabling;
The procedure body for Grid_Random_Fill needs to agree with the specification, which is:
procedure Grid_Random_Fill(A : in out Grid);
The body does not include the parameter A.
The solution will involve two nested loops, over the range of the two dimensions in the array you declared.
And the simple answer :
with Ada.Numerics.Discrete_Random;
with Ada.Text_Io;
procedure Main is
type Cell_T is (M,V);
type Rows_T is new Integer Range 1 .. 40;
type Cols_T is new Integer Range 1 .. 80;
type Grid_T is array (Rows_T,Cols_T) of Cell_T;
package Rand is new Ada.Numerics.Discrete_Random (Cell_T);
G : Rand.Generator;
Grid : constant Grid_T := (others => (others => Rand.Random(G)));
begin
for R in Rows_T'range loop
for C in Cols_T'range loop
Ada.Text_Io.Put (Cell_T'Image (Grid (R,C)));
end loop;
Ada.Text_Io.New_Line;
end loop;
end Main;
Output :
$ ./main
VMMVVMMMVMMMVVVMMMVVVMMVVVMVVVVMMMMVMMMMVVMVMVVMMVMMMVVMMMMVMMVMMVMMMMVMMVVMVVMM
VVVMVVVVMMMMMMVVMVMMVMMMVMMMVVMVVVVVMVVVMVMVVVMVMVVVMVMMMVMVVVMVMMVVVMVVMVVVVVMM
VVMVVVVVVVMVVVVMVVVMVVMMVMVVVMVMMMVMMMVVVMMMVVVMMMMMVVVVMVMVVVVVVVMMVVMVMVMMVVVM
VMMVVMVMVVMVMVVMMVMMVMVVMVMVMMVVMMVVMMVMVVVVVVMVMVMMMMMMVMVVVMMVMMMMVMVVVVMVMVVM
VVVVMMMMMVVMMMMVVMMMVMMMVVMVVVMMMMMMVMVMMVMMVVVMMVMMMMVVMVMVMMMMVMMMVMVVVVMMMVMM
VMMVVMMMMMVVMMMVVVVMMVMMVVVVVVVVVVMVMVMVVVVVVVVMVMVMVVMVMMMMMVMMVVVVVVVVMVVVVVVV
VVMMMMVVVMMVMVMVMVVMMMMMVMVVVVMMVVMVVVMMMMMMMMMMMMMVMMVVMVVMVMMVMMMVVVMMMVVVMVVV
MVMVMMVMVVVMVVVVVVVMMMMVVVMMVVVMVMMVVMVVVMVMVMMMMVVVVMVVMMVMVMVVVMVMMVMMMVVMVVVV
MMVMMVMMMVVVVMVVVVVVVMVVVVMMMVMMMVMVMMMVMVVVMVMMVMVMVMVVMMMVVVVVMVVMVMVMVVMMMVVV
VVMMMMMMMVMVVMVMVVVMVVMVMMMMMVVVVVVVMVMMVVMMMMVVVMVVMVVMVVVVMMVVVVMMMMVMMVMMMMMM
VVVMMMMVMMVVVVVMVVMVVMVMMMMMMVMMMMVVMVVVMVMVVMMVVMMMVVMMMVMVVVVVMMVVVMVVVMMVVMMM
VMVVMMVMVVVMMMVVVVMMMMVVVMVVVVMMMVMVVVVMMMVVVMVVMMVVVMVMMMVMMVVVMVMMMMMMVMVVVMVV
VMVMMMVMMMVMMMMMMVMMMVVMMMMVMMMVVMMVMMMVVMVVVMMMMVMVMVMVVMMVMMMVVMVVMVMMMMVMVMMM
VMVVVMMMMMVMMMMVVVVMMMVVMMVVMVVMVMVVMVVVVMVMMVMMVMMVMVVMVVVVVVMMMMVMVMMMVVVMMVVV
VVMVVMVMVVVMMMMMVVVMVMVVMVMVMMVVVMVVMMVMMVMMVVMVMMMMVMVVMMMVVMVMMMMMMMMVMVMMVVVM
MVVVVVMMVVMMMVMVMVMVMVVMMMVVMMVMVMVVVMVVVVVMMMMVVVMVVMVVMVVVVVVVVMMVMMVVVVVVVVMV
MVMMMMVMMVVVVVMMMVMVVVMVVMVVMVVVVMVVVMVVMVVMMVVVMVMVVMMMVVMMMMVVMMMVMVMMMMVMMMVV
MVVMVMVVMMVMVMMVMVVVMVVVVVVVVVVVVMVMMVVMMVMMMVVVMMVMMMMVVMVMVMVMVMVVVMMMMVMVVVMM
MMVVVVVMVVMVMMVMMVVVVVMVMMMMMVVVVMVMVMMVVVMMMVMVVVMVMMMMVVMMVMVMVVVVMMMVMMMMVVMV
MMMVVMMMVMVVVVVMVMVMMVVVMVVMMVMVVMVVMVMMVMVVVVVVVMMMVVVMVVVVMVVVVVVMMMVVMMMMMMMV
VVMMVMMVMMMMVMVVVMMMMVVMVMVVMVVVMMMVMVMMMMMVMMVVMMMMVMVVMMMVMVMMMMVMMMMVVVMMMVMM
VMVVVMMVVVVVVMVMMMVVVMVMMVVMVVMVVVVVVVVMMMMMVVVMMMMVMVVVMVMVMMVVVMMVMMVMVMMVVVVV
MMVMMMVMVMVMMVVMMMMVMMVMVMMVVMMMVVVMVVVVVVVVMMMVMVVVMMMVMMVMMVMVMVMMMVVMMMMMVMMM
MMVVMMMMMVVMMMMVMVVMVVMVVVVVMVVVMVMMVMMVVMMMVVVMVVVVMVVMMVVMVVMMMVMVMVMVMVMMMMVM
MVMVVVVMMMVVMVVMMVMVVMVMVVVMMVMVMMMVMVMMMMMVMVMVVMMVMMMVMVMVVMMVMMMVVMVVVVVMVMVV
VMVVMMMVMVMMMMMMMMVVVMVMVVVVMVVVVVMVMVVMVMVVVVVMMVVVVVVMMMMMVVMVMVVVVMVMMMMVVVVM
MVMVMVMMMMVMMVVVMMMMMVMMVVMMMMVVVVVVVMMVVVVMMMMMVVMMVVMVVVVVMMMVVVVMVMVVVMMVMMVM
VVVVVMMMMVVMMMMVVMVVVMMVMMVMVVVVVMVVVVVMVMVVMMVVVMVVMMMVMVVVVMMMVVVMVVMVMVMMMMVV
MVVVMVMVMVMMMMMVMVMMVMMVVMVVVVMMVMVVMVVVMVMVMVMMVVVVMMVVMMMVVVMMMMMVVMMMMMVMVVVV
MVMVMMMVVVMVVVVVVMMVMVVVMMVMVMMVMMVMVVVMMMMVMMVMMVMMMMMMVMVVVMVMMVMVMMMVVMMMMVMV
VVMVVMVVMVMVMMMMVMVVVMMMMMVMMMMMMMVVVVVMMMVVVMVMMMMVVVMVMVMVVMMMVMMMMVMMMVMMMVMV
MMMMVMMVVVVMVVMMVMVVMVVVMVMMVVVMVVVMMVVVVVMMMVMVVVMMMMVVMVMMVMVMVMVMMMVMMVVVMMMM
VMMMMVVMMVMVMVVVVVMVVVMVMMMVVMMMVVMVVVMMMMVVVVMVMMVVMMVVVVMMMVMVMVVMVMMVMVMMMMMV
MMMMVMMMMMVMMVMMMVMVVMMVVVMVMMVVMVMVVMVVMMMMMVMVVVMVVMMVVVVMMMMMMMMVMVVVMVVMVMVV
VMMVMMMMMVMVMMMVVVVVMVMVMVMMVMVMVVVVVVVMMMMVVMMVVVMVVVMMMVVVMMVMMVVVMVVVMVMMMVMM
VMVMMVVVMVMMMMVVVMMVMMMVVVVMVMVVVMMVMMVMMVVVMMMMMVVVMVMMMMVVMVVVMVVMMMVMMMVMVVVM
VVVMMMVVMMMMMVMVVVMVVMVVVVVVMMMVVMVVMVVMVMVMVVVMVMMMMVMMMMMVMMMMVVMVVVVVVMVMMVMV
VVVVMVVVMVMMMMMMVVMVVVVVVMMMMMMVVMMMMVMMVMMVMMMVMVVMMMMMVMMMMMMMMVVVMMMMVVMVMVVM
MMVVVMVMVVMVVMVVVMMVVMVMVMMVMMMVMVMMMMMVVVMMMMVMMVMVVVVMVMMMMVVVMMMVVVMMMVMMMMMM
VMMVMMMVMVVMMVVVVMMVMMVVMVMVMMVMMMVMMVVMVVVVMVMVVVVMMMMMMMVVVMVMVMMVVVVMVMVMMMVV

list of unique random numbers in an Interval in Ada

I'm sorry to bother you I know this question have been asked quite a lot but never with Ada... I was wondering if there were in the Ada standard library a way to generate a list of unique random numbers (you never pick twice the same number) in O(n)
In a way is there an implementation of the Knuth-Fisher-Yates algorithm in Ada?
There's a discussion of implementing the Fisher–Yates shuffle here. Basically, you need a different range of Discrete_Random in each iteration, as shown here; Float_Random is an alternative, as mentioned in A.5.2(50), Note 16. If bias isn't critical, this example may be sufficient.
In any case, shuffling is O(n), but selecting can be O(1).
Addendum: The complexity of creating the set depends on the implementation. For example, Containers.Hashed_Sets, A.18.8(88/2) and Containers.Ordered_Sets, A.18.9(116/2).
Given that you want:
a) Random numbers from 0 to 1000
and
b) the numbers are not to repeat
according to the link you provided, you could do this rather easily.
Just fill an array with the range of values and perform some number of swaps on randomly chosen elements thereof; this guarantees both requirements are upheld.
I took the liberty of coding it up.
You'll need to With Ada.Numerics.Discrete_Random.
Generic
Low, High : Integer;
Package Initialization is
SubType Element is Integer Range Low..High;
Function Incrementor Return Element;
Type Element_Array is Array(Element) of Element;
Values : Element_Array;
Procedure Print;
End Initialization;
Package Body Initialization is
Count : Element := Element'Last;
Function Incrementor Return Element is
begin
Return Result : Element:= Count do
Null;
Count:= Element'Pred( Result );
Exception
When Constraint_Error => Count:= Element'Last;
End Return;
end Incrementor;
Procedure Swap( Index_1, Index_2 : In Integer ) is
Temp : Constant Element:= Values( Integer(Index_1) );
begin
Values( Integer(Index_1) ):= Values( Integer(Index_2) );
Values( Integer(Index_2) ):= Temp;
end Swap;
Procedure Print is
begin
Put_Line( "Length: " & Values'Length'Img );
Put( "(" );
For Index in Values'First..Integer'Pred(Values'Last) loop
Put( Values(Index)'Img & ',' );
end loop;
Put( Values(Values'Last)'Img );
Put_Line( ")" );
end Print;
Begin
Shuffle:
Declare
Package Random_Element is New
Ada.Numerics.Discrete_Random( Element );
Number : Random_Element.Generator;
Use Random_Element;
Begin
Values:= Element_Array'( Others => Incrementor );
Reset( Number );
For Index in Element'Range loop
Swap( Integer(Index), Integer(Random(Number)) );
end loop;
End Shuffle;
End Initialization;
And you can test it out with something like:
Test:
Declare
Package Q is new
Initialization( Low => 0, High => 1000 );
Begin
Q.Print;
End Test;

Resources