VHDL array concatenation of varying types - concatenation

I am doing some undergraduate research that involved some VHDL coding, something i have virtually no experience with. I am running into some issues and hoping for some help:
I need to read in a signal (array of "std_logic_vectors"), and perform a logical shift on it. My thought was to concatenate an array of 0's with an array that contains the relevant portion of the input. Here is what i've done:
Library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.SignalGen.all;
entity Shifter is
Port ( xsig_in : in SignalGen;
shift : in integer;
clk : in STD_LOGIC;
x_out1 : out SignalGen;
x_out2 : out SignalGen);
end Shifter;
architecture Behavioral of Shifter is
type x_in_type is array (0 to (1024-shift) of std_logic_vector;
type zeroes_type is array(0 to shift) of std_logic_vector;
signal x_shifted: SignalGen;
signal x_in : x_in_type := xsig_in(1024 downto shift); -- This is line 37
signal zeroes : zeroes_type := (others => (others => '0'));
begin
process(clk)
begin
x_shifted <= zeroes & x_in; -- This is line 49
end process;
end Behavioral;
Its important to know what type SignalGen is, so here is my declaraion:
type SignalGen is array (0 to 1024) of STD_LOGIC_VECTOR(15 downto 0);
So as you can see, I've created a type "zeroes_type", which is the length of the desired shift. It is used to generate a signal "zeroes" filled with zeroes. Also x_in is of type x_in_type, which is the length of the input signal minus the shift amount, and is initialized to be the signal minus the values shifted out.
When i try to concatenate them together, I get these errors:
Line 37: Indexed name is not a x_in_type
Line 49: found '0' definitions of operator "&", cannot determine exact overloaded matching definition for "&"
The line numbers are included in comments in the code posting. I've been tinkering with this segment for hours now and nothing i've tried to do can fix it.
If anyone can shed some light on the matter, or give me a better way to do what I am trying to do, I would be extremely appreciative! Thanks!

I think you were a long way from where you needed to be. This will not be an efficient implementation in terms of area: you will have 16,000+ flip-flops. However, this solution ought to be closer to where you need to be:
Library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use work.SignalGen.ALL;
entity Shifter is
Port ( xsig_in : in SignalGen;
shift : in integer;
clk : in STD_LOGIC;
x_out1 : out SignalGen;
x_out2 : out SignalGen);
end Shifter;
architecture Behavioral of Shifter is
begin
process(clk)
variable V : SignalGen;
begin
if rising_edge(clk) then
V := xsig_in;
for I in 1 to xsig_in'RIGHT loop
if I <= shift then
V := "0000000000000000" & V(0 to xsig_in'RIGHT-1);
end if;
end loop;
x_out1 <= V;
end if;
end process;
end Behavioral;
http://www.edaplayground.com/x/8AQ
Variables, loops and concatenation are often useful when doing shifting as you can see in my example. You can jump out of the loop (using exit) when you're finished shifting, but my experience you might get slightly more logic doing that, ie:
if I <= shift then
V := "0000000000000000" & V(0 to xsig_in'RIGHT-1);
else
exit;
end if;
There are many errors in your code. Whilst, I'm sure you will learn something from me just posting the answer, here are some explanations about the errors you are seeing:
type x_in_type is array (0 to (1024-shift)) of std_logic_vector;
You were missing a right hand parenthesis and this line relies on you using VHDL 2008, because the inner dimension is unconstrained. But even then, you cannot define a type based on a non-static quantity (shift), anyway.
signal x_in : x_in_type := xsig_in(1024 downto shift);
With you array constrained as it is, you need to skip over the outer dimension to constrain the inner one. In VHDL 2008 you can skip over a constrained dimension like this:
signal x_in : x_in_type := xsig_in(open)(1024 downto shift);

Related

How to partially constrain VHDL arrays (elements)?

I am trying to use unconstrained arrays in a VHDL-2008 testbench, but Modelsim (2020.1) gives an error if I try to declare a file type.
This simplified example reproduces the error:
entity tb is
end entity;
architecture arch of tb is
type array_t is array(natural range<>) of bit_vector;
subtype sub_t is array_t(open)(15 downto 0);
type file_t is file of sub_t;
begin
end architecture;
vcom -2008 tb.vhd
# ** Error: tb.vhd(8): Cannot define file of an array whose element subtype is not fully
constrained.
I am confused by this error message because, as far as I understand, the element subtype is fully constrained. I had a look in VHDL 2008: Just the New Stuff which says (in Section 3.1.2):
If we want to define a partially constrained subtype, specifying index
ranges for the elements but leaving the index range at the top level
unspecified, we can use the reserved word open in place of an index
range
So why do I get this error? As a sanity check, the following compiles without error:
entity tb is
end entity;
architecture arch of tb is
type array_t is array(natural range<>) of bit_vector(15 downto 0);
subtype sub_t is array_t;
type file_t is file of sub_t;
begin
end architecture;
I don't really understand what the exact differences are between the declarations of sub_t in each case (and why one should work whereas the other fails).
Thanks for the help!

Assign the values for an array in Ada

I'm approaching the Ada language. I wrote this simple program that loops over an array and increments every single value, but the compiler gives me an error of type:
hello.adb:8:07: left hand side of assignment must be a variable
The program in question is this:
with Ada.Text_IO;
procedure hello is
type myArrayDefinition is array (1 .. 10) of integer;
myArray : constant myArrayDefinition := (1 => 3, others => 2);
begin
for A in 1 .. 10 loop
myArray(A) := myArray(A) + 1;
end loop;
end hello;
Could anyone help me to understand the problem?
You can't modify the value of a constant. There are no special problems related to modifying the values of arrays.

Copy arrays of same type and size but different index type in Ada

I am learning Ada at the moment and the current lesson is on arrays. Consider the following program;
procedure Main is
type T_Bool is array (Boolean) of Integer;
type T_Intg is array (Integer range 1 .. 2) of Integer;
A1 : T_Bool := (others => 0);
A2 : T_Intg := (others => 0);
begin
-- None of these statements work
A2 := A1;
A2 (1 .. 2) := A1 (false .. true);
A2 := A1 (Boolean'First .. Boolean'Last);
end Main;
According to the Adacore university tutor, it is possible to copy values from one array to another as long as the lengths are the same. In the code snippet, why can you not assign arrays with the same size but different indexing methods, despite the fact that the length is the same?
What is the correct way to copy this across? Is it a case of looping through all indexes in the Boolean type range and copying the corresponding array index across or is there another clever way of doing it?
The tutorial says, on slide 3, that "all arrays are (doubly) typed", which means that - as usual for different types - you can't assign between your two array types; so yes, you need a loop.
There are "clever" ways using, for example, unchecked conversion; but, really, don't go there!
It is possible to copy arrays without any explicit conversion if they are of the same type and length with only the starting index differing:
procedure Test is
type T is array (Positive range <>) of Integer;
A : T(1 .. 10);
B : T(21 .. 30);
begin
A := B;
end Test;
Otherwise it is possible to assign arrays of different type with explicit conversion, but apart from having the same dimensionality (and more, see ARM 4.6) the index types also have to be convertible. Boolean is an enumeration type which is not convertible to Integer.
Explicit conversion with convertible index types would look like this:
procedure Main is
type TMod is mod 10000;
type T_Mod is array (TMod range 5000 .. 5001) of Integer;
type T_Intg is array (Integer range 1 .. 2) of Integer;
A1 : T_Mod := (others => 0);
A2 : T_Intg := (others => 0);
begin
A2 := T_Intg(A1);
end Main;
So yes, it would look like you need to copy elements in a loop in your example.
Thanks for your answers guys, it is definitely useful information. It goes even deeper than I thought. In the quiz part of the tutorial, I learned that even this is an error
procedure Main is
type T1 is array (Integer range 1 .. 10) of Integer;
type T2 is array (Integer range 1 .. 10) of Integer;
A1 : T1;
A2 : T2;
begin
A1 := (others => 0);
-- Cannot do this
A2 := A1;
end Main;
Types A2 and A1 may well be defined in the same way, but Ada considers them unrelated and therefore incompatible. It would be the equivalent in C++ of doing
typedef int MyType1;
typedef int MyType2;
MyType1 MyVar1;
MyType2 MyVar2;
// Error - Cannot assign differing types,
// despite them being semantically the same
MyVar2 = MyVar1;
In this particular case (or when there are only few values for index), it is possible to assign in once with an aggregate.
A2 := (1 => A1 (False),
2 => A1 (True));
The complete example:
https://gcc.godbolt.org/z/josscfPzh

VHDL Simple code optimization

Here is my code :
variable input: array(0 to 3, 0 to 3) of unsigned(7 downto 0);
variable outt: array(0 to 3, 0 to 175) of unsigned(7 downto 0);
for i in 0 to 3 loop
outt(0,i) :=input(0,i);
outt(1,i) :=input(1,i);
outt(2,i) :=input(2,i);
outt(3,i) :=input(3,i);
end loop;
Is there a better way to do this?I mean an efficient code to copy all of input array in a part of the larger outt array ?
As a rule of thumb for loops in VHDL are unrolled, as the purpose of a loop is to synthesize multiple copies of hardware described in the loop body. The control logic does not appear in the synthesized hardware.
For that reason, a more compact way to write multiple assignments is to do two nested loops.
for i in 0 to 3 loop
for j in 0 to 3 loop
out(i,j) := in(i,j); // there will be 16 wires / flipflops synthesized
end loop;
end loop;
Try
outt(0 to 3, 0 to 3) := input;
For maximum flexibility, you can use nested loops and attributes to cope with changes in the size of i:
for i in i'range(1) loop
for j in i'range(2) loop
outt(i,j) := input(i,j);
end loop;
end loop;

How to use 'Last attribute on multidimensional arrays in Ada?

I am trying to use the 'Last attribute with a 2D array in Ada, but I can't seem to find the correct syntax to do so.
I know that if I have a 1D array/vector I can use A'last or A'last(n) where n is the nth dimension. But if I do the following
type UnconstrainedArray_2D is array (Integer range <>, Integer range <>) of Integer;
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
for i in 0..tempTable'last(1) loop
for j in 0..tempTable'last(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
end temp;
I get the following compile time error:
Storage_Error stack overflow (or erroneous memory access)
So what am I doing wrong?
I am using GNAT Pro 6.4.1 on Linux.
I'd be very surprised if you got a compile-time Storage_Error on that code.
I've grabbed a copy of your code and modified it as follows; it compiles without error using GNAT (gcc-4.4):
procedure Array_2D is
type UnconstrainedArray_2D is array (Integer range <>, Integer range <>) of Integer;
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
for i in 0..tempTable'last(1) loop
for j in 0..tempTable'last(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
return 42; -- added this
end temp;
begin
null;
end Array_2D;
(Note that I had to add the missing return statement in temp.)
Your syntax for the 'Last attribute (not "command") is correct, but since Ada arrays can have arbitrary lower and upper bounds, it's better to use the 'Range attribute instead:
for i in tempTable'Range(1) loop
for j in tempTable'Range(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
As for the Storage_Error exception, that could easily happen at run time (not compile time) if you call your temp function with a very large value for tempIn. Remember that it has to allocate enough space to hold tempIn**2 Integer objects. Presumably you've also created another UnconstrainedArray_2D object to be passed in as the Table parameter.
It's conceivable that the compiler itself could die with a Storage_Error exception, but I don't see anything in your code that might cause that.
Show us a complete (but small) program that demonstrates the problem you're having, along with the exact (copy-and-pasted) error message. Please distinguish clearly between compile-time and run-time errors.
Your tempTable might have a range of 0..tempIn, but you don't know what range your Table has.. They could be of different length, too.
You would have to check that the length is the same and then use relative indices, like this:
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
if tempTable'Length (1) /= Table'Length (1) or else
tempTable'Length (2) /= Table'Length (2)
then
raise Constraint_Error; -- or something else
end if;
for i in 0 .. tempTable'Length (1) - 1 loop
for j in 0 .. tempTable'Length (2) - 1 loop
tempTable(tempTable'First (1) + i, tempTable'First (2) + j) :=
Table(Table'First (1) + i, Table'First (2) + j);
end loop;
end loop;
end temp;
that way it is ensured that both tables are same length and all indices are valid.
If your tempTable is allowed to be smaller than Table, simply adjust the length check to >. The indices would still be valid.
I don't see an actual value for tempIn set. If the value for tempIn coming into the function temp has not been properly initialized or explicitly set, then the value in tempIn could be anything and probably not something you would like.
I was thinking of a default value. (probably shouldn't post when I am not feeling well :-)

Resources