I have a VHDL design question.
I have N similar entities which take some input and each of them generates
an STD_LOGIC output.
Example:
entity example1 is
begin
...
result_1 : out std_logic;
end example1;
entity example2 is
begin
...
result_2 : out std_logic;
end example2;
...
I am looking for a way to aggregate all those single bit results in one UNSIGNED(N - 1 downto 0) result signal V such that V(i) = result_i holds.
Currently, my approach looks like this:
entity ResultAggregation is
port (
result_1 : in std_logic;
result_2 : in std_logic;
aggregate_results : out unsigned(1 downto 0)
);
end ResultAggregation;
architecture Behavioral of ResultAggregation is
begin
aggregate_results <= result_2 & result_1;
end Behavioral;
I find this approach rather clumsy. What I am looking for is a more automated solution,
for example that I can provide the number N such that the appropriate pins are generated.
I know this is a rather generic question, but if somebody knows a clever solution please
let me know.
Thanks in advance,
Sven
My suggestions would be to omit the ResultAggregation entity and only define a aggregate_results signal on the same level as your example1, example2, etc. entities. You could then instantiate these entities as
i_example1 : entity work.example1
port map (
...
result_1 => aggregate_results(0));
i_example2 : entity work.example2
port map (
...
result_2 => aggregate_results(1));
You could make the width of the aggregate_results vector a generic on the level where you instantiate the example1 etc. entities.
The only way you can get a generic number of pins would be to define your ResultsAggregation entity as
entity ResultAggregation is
generic (
N_RESULTS : integer
);
port (
results : in std_logic_vector(N_RESULTS-1 downto 0);
aggregate_results : out std_logic_vector(N_RESULTS-1 downto 0)
);
end ResultAggregation;
But then this entity would only contain the statement aggregate_results <= results which makes this entity pointless.
use a for/generate statement if blocks are identical:
n_examples: for i in 0 to (N-1) generate
inst_example: example_entity
port map(
...
result => V(i);
);
end generate n_examples;
if blocks have similar entity but different funcitonality, you can still use this approach:
...
inst_ex1: example1
port map(
...,
result_1 => V(1)
);
inst_ex2: example2
port map(
...,
result_2 => V(2)
);
....
Related
I am currently working on programming this (https://rosettacode.org/wiki/Cartesian_product_of_two_or_more_lists) in Ada, I am trying to do a Cartesian product between different sets. I need help figuring it out, the main issue is how would I be able to declare empty Pairs and calculate that if it's empty, then the result should be empty. Thank you!
Numbers I am trying to use:
{1, 2} × {3, 4}
{3, 4} × {1, 2}
{1, 2} × {}
{} × {1, 2}
My code:
with Ada.Text_IO; use Ada.Text_IO; -- Basically importing the functions that will be used to print out the results.
procedure Hello is -- Procedure is where variables & functions are declared!
type T_Pair is array(1..2) of Integer; -- Declare a type of array that contains a set of 2 numbers (Used for final result!).
type T_Result is array(1..4) of T_Pair; -- Declare a type of array that contains a set of T_Pair(s), used to hold the result.
Demo1 : T_Result;
Demo1A : T_Pair := (1, 2);
Demo1B : T_Pair := (3, 4);
function Fun_CartProd(p1: T_Pair; p2: T_Pair) return T_Result is
results: T_Result;
i: integer := 1;
begin
for j in 1..2 loop
for h in 1..2 loop
results(i) := (p1(j), p2(h));
i := i + 1;
end loop;
end loop;
return results;
end Fun_CartProd;
begin -- This is where the statements go
Demo1 := Fun_CartProd(Demo1A, Demo1B);
for K in 1 .. Demo1'length loop
Put(" [");
for B in 1 .. Demo1(K)'length loop
Put(Integer'Image(Demo1(K)(B)));
if Demo1(K)'length /= B then
Put(",");
end if;
end loop;
Put("]");
if Demo1'length /= K then
Put(",");
end if;
end loop;
Put_Line(""); -- Create a new line.
end Hello;
Since each set of integers can be any length, including empty, I would start with a type that can handle all those situations:
type Integer_Set is array(Positive range <>) of Integer; -- Input type
type Integer_Tuple is array(Positive range <>_ of Integer; -- Output type
and you can represent the empty sets and tuples this way:
Empty_Set : constant Integer_Set(1..0) := (others => <>);
Empty_Tuple : constant Integer_Tuple(1..0) := (others => <>);
The other problem isn't just how many elements are in each set, but how many sets you will be finding the product of. For this I would recommend some kind of container. An array won't work here because each of the individual sets can have different sizes (including empty), but Ada has a variety of "indefinite" containers that can handle that. Here is an example using vectors:
package Set_Vectors is new Ada.Containers.Indefinite_Vectors
(Index_Type => Positive,
Element_Type => Integer_Set);
package Tuple_Vectors is new Ada.Containers.Indefinite_Vectors
(Index_Type => Positive,
Element_Type => Integer_Tuple);
and you can then represent an empty result as:
Empty_Tuple_Vector : constant Tuple_Vectors.Vector := Tupler_Vectors.Empty_Vector;
Now you can create a function that takes in a vector of sets and returns a Cartesian product which will also be a vector of sets:
function Cartesian_Product(Inputs : Set_Vectors.Vector) return Tuple_Vectors.Vector;
If one of the input sets is empty, you return an Empty_Tuple_Vector. You can check if one of the input sets are empty by checking their Length attribute result. It will be 0 if they are empty. Additionally if the input vector is completely empty, you can decide to either return Empty_Tuple_Vector or raise an exception. For example:
if Inputs'Length = 0 then
return Empty_Tuple_Vector; -- or raise an exception, etc.
end if;
for Set of Inputs loop
if Set'Length = 0 then
return Empty_Tuple_Vector;
end if;
-- Maybe do other stuff here if you need
end loop;
Note that the logic you presented assumes only pairs of inputs. I don't have enough experience to convert your logic to account for variable inputs, but perhaps someone can comment on that if you need it.
Also note as Flyx commented, this does not semantically check if a set is a set or not on the inputs (I.E. no duplicate values).
I created the following example code:
type Category is (A, B, C);
type My_Record (The_Category : Category) is record
case The_Category is
when A =>
A : Natural;
when B =>
B : Integer;
when C =>
A : Natural;
B : Integer;
end case;
end record;
The code is obviously not valid in Ada because I am getting two compiler errors: "A/B" conflicts with declaration at line ...
Why is such definition of a variant record not supported in Ada? I think it could be useful. Are there other ways to model this kind of data structure?
I ran into this problem recently. This is a case of Ada having your back. The Adaic (Pythonic equivalent?) way would be something like:
type Category is (A, B, C);
type A_Data is
record
A : Natural;
end record;
type B_Data is
record
B : Integer;
end record;
type C_Data is
record
A : Natural;
B : Integer;
end record;
type My_Record (The_Category : Category) is record
case The_Category is
when A =>
A : A_Data;
when B =>
B : B_Data;
when C =>
C : C_Data;
end case;
end record;
While verbose, this provides strong typing as to what you have access to. The usage is nearly identical, the main difference is that in the C category things look uniform:
case My_Object.The_Category is
when A =>
Use_Integer (My_Object.A.A);
when B =>
Use_Natural (My_Object.B.B);
when C =>
Use_Integer (My_Object.C.A);
Use_Natural (My_Object.C.B);
end case;
A lot of people take some time to get used to Ada's verbosity, but over time you learn to love it. This larger interface compiles to nearly identical code and is much more open to extensibility (what if category A items now also need a float? instead of changing all A category items, just change the A_Data type).
It is not supported because it might confuse a reader (or a developer).
The fields in the different branches are logically different fields, so using the same name would be confusing.
(This is my explanation. If there exists an official one, you can find it in the Ada 83 Rationale.)
I practice you do something like this:
type Categories is (A, B, C);
type Data (Category : Categories) is record
case Category is
when A =>
Identifier_1 : Natural;
when B =>
Identifier_2 : Integer;
when C =>
Identifier_3 : Natural;
Identifier_4 : Integer;
end case;
end record;
You have to come up with some actual, sensible naming yourself, as I don't know which problem you're trying to solve.
when 'B' |'b' =>
cons.Put_Line("Enter text - less than 20 chars: ");
cons.Get_Line(Item => st,
Last => m);
--buffer_ser'Write(st,m);
ser.Write(Port => S_Port,
Buffer => buffer_ser);
Defined as:
package cons renames gnat.IO;
package ser renames gnat.Serial_Communications;
S_Port : gnat.Serial_Communications.Serial_Port;
buffer_ser: ada.Streams.Stream_Element_Array(1..20);
x : Ada.Streams.Stream_Element_Offset;
m : Integer;
st : string(1..20) := (others => ASCII.NUL);
ComPort : GNAT.Serial_Communications.Port_Name(1..5);
Basically, I needed a very portable application, to operate an old device that overlays a video stream based on serial commands. I decided to try out Ada as I'd been learning it for something else.
How do I convert to a Stream_element_array(1..20) from a String(1..20) in Ada? I've tried the obvious answers, and I'm just totally stuck!
Edited as requested for the person who down voted me...
First we need an MCVE.
with gnat.IO;
with ada.Streams;
with gnat.Serial_Communications;
procedure MCVE is
package cons renames gnat.IO;
package ser renames gnat.Serial_Communications;
S_Port : gnat.Serial_Communications.Serial_Port;
buffer_ser: ada.Streams.Stream_Element_Array(1..20);
x : Ada.Streams.Stream_Element_Offset;
m : Integer;
st : string(1..20) := (others => ASCII.NUL);
ComPort : GNAT.Serial_Communications.Port_Name(1..5);
begin
cons.Put_Line("Enter text - less than 20 chars: ");
cons.Get_Line(Item => st,
Last => m);
--buffer_ser'Write(st,m);
ser.Write(Port => S_Port,
Buffer => buffer_ser);
end MCVE;
it compiles successfully and fails with the error
raised GNAT.SERIAL_COMMUNICATIONS.SERIAL_ERROR : write: port not
opened
A little reading on Streams shows that the answer to the actual question:
How do I convert to a Stream_element_array(1..20)
is : normally, you don't. Streams take care of that for you.
A couple of modifications, respectively:
make S_Port aliased so we can take its access (to allow redirectable stream Writes) and delete unnecessary intermediate variables
actually open the serial port as a Stream
write the string directly to the stream
look like
S_Port : aliased gnat.Serial_Communications.Serial_Port;
-- buffer_ser: ada.Streams.Stream_Element_Array(1..20);
-- x : Ada.Streams.Stream_Element_Offset;
...
gnat.Serial_Communications.Open(S_Port,ComPort);
String'Write(S_Port'access, st(1..m));
--buffer_ser'Write(st,m);
--ser.Write(Port => S_Port, Buffer => buffer_ser);
But using fixed length strings when they aren't appropriate is a bad idea. Let's declare the string to be of the right length and simplify further. This requires a function form of Get_Line, which the Gnat.IO package doesn't provide, so let's use the more portable Ada.Text_IO instead. (And initialise the serial port name, and actually use the renamed packages...)
When we're done, we have something like
with Ada.Text_IO;
with ada.Streams;
with gnat.Serial_Communications;
procedure MCVE is
package cons renames Ada.Text_IO;
package ser renames gnat.Serial_Communications;
S_Port : aliased ser.Serial_Port;
ComPort : ser.Port_Name := "COM1";
begin
ser.Open(S_Port,ComPort);
cons.Put_Line("Enter text : ");
declare
st : String := cons.Get_Line;
begin
String'Write(S_Port'access, st);
end;
end MCVE;
I am having trouble creating a thick pointer. My current set of declarations look like this:
type Index_Typ is mod 20; -- will be larger in real life
type Data_Buffer_Typ is array (Index_Typ range <>) of Integer; --unconstrained array type
type Data_Buffer_Ptr is access all Data_Buffer_Typ; -- a thick pointer, contains the bounds of array subtype pointed to and address..
Data_Buffer : aliased Data_Buffer_Typ (Index_Typ) := (others => 0); -- this is private
type Result_Typ is (Ok, Overflow, Null_Pointer);
procedure Retrieve (Index : in Index_Typ;
Len : in Index_Typ;
Data_Ptr : out Data_Buffer_Ptr;
Result : out Result_Typ) is
begin
-- assuming range checks are ok, what goes here ?
end Retrieve;
so if i declare:
Ptr : Data_Buffer_Ptr := null;
and given a call of Retreive (2,3, Ptr,Result); how do i end up with a pointer that points at elements 2,3 & 4 of Data_Buffer ?
Notes:
Yes i know passing out an array slice will probably be done as a
pointer anyway, but we want to explicitly use pointers, not
implicitly (and not my choice!).
Yes i have experimented, i usually get : (object subtype must statically match designated subtype) error message..
Where possible use of new to be avoided.
This works for me, though I have to say it's repulsive! Note the order of the components in Fat_Pointer, which is the opposite to what I started with, and the size of the record on this 64-bit machine (I put the rep clause in to have make the order explicit, it works fine without). Also, I think you're stuck with the new.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Conversion;
with System;
procedure Fat is
type Index_Typ is mod 20;
type Data_Buffer_Typ is array (Index_Typ range <>) of Integer;
type Data_Buffer_Ptr is access all Data_Buffer_Typ;
Data_Buffer : aliased Data_Buffer_Typ (Index_Typ) := (others => 0);
type Result_Typ is (Ok, Overflow, Null_Pointer);
procedure Retrieve (Index : in Index_Typ;
Len : in Index_Typ;
Data_Ptr : out Data_Buffer_Ptr;
Result : out Result_Typ)
is
type Bound is (Lower, Upper);
type Bounds is array (Bound) of Index_Typ;
type Bounds_P is access Bounds;
type Fat_Pointer is record
The_Data : System.Address;
The_Bounds : Bounds_P;
end record;
for Fat_Pointer use record
The_Data at 0 range 0 .. 63;
The_Bounds at 8 range 0 .. 63;
end record;
function To_Data_Buffer_Ptr
is new Ada.Unchecked_Conversion (Fat_Pointer, Data_Buffer_Ptr);
Answer : constant Fat_Pointer
:= (The_Bounds => new Bounds'(Lower => Index,
Upper => Index + Len - 1),
The_Data => Data_Buffer (Index)'Address);
begin
Result := Ok;
Data_Ptr := To_Data_Buffer_Ptr (Answer);
end Retrieve;
Ptr : Data_Buffer_Ptr := null;
Result : Result_Typ;
begin
for J in Data_Buffer'Range loop
Data_Buffer (J) := Integer (J);
end loop;
Retrieve (2, 3, Ptr, Result);
for J in Ptr'Range loop
Put_Line (J'Img & " => " & Ptr (J)'Img);
end loop;
end Fat;
I hope this is possible. I want to be able to write recursive code like this:
entity myEntity
generic (
size : natural -- a power of 2
)
port (
-- whatever
);
end;
architecture structural of myEntity is
begin
smallerEntity : entity component.myEntity(structural)
generic map (
size => size/2
);
port map (
...
);
end;
So each architecture instantiates a smaller version of itself. At some value of the generic 'size' I want to have a different implementation however.
Can this be done with configurations? If so, how?
As to why I'd like to be able to do this - so I can build reusable code for computing FFTs/DCTs and similar transforms.
You can use recursion in VHDL. But you need to encapsulate your instantiation in an if-generate statement. Something like:
recursive_structure : if size/2 > 0 generate
smallerEntity : entity <library_name>.myEntity(structural)
generic map (
size => size/2
)
port map (
...
);
end generate recursive_structure;
I use a function like:
-- convert natural to min vector length
function min_len_uns(arg : natural) return natural is
begin
case arg is
when 1 | 0 =>
return 1;
when others =>
return 1 + min_len_uns(arg/2);
end case;
end;