Alias of two std_logic_vector elements of an array

H

hhanff

Hello!

I declared the following type and the corresponding signal:

type sd_card_data_a is array (natural range 527 downto 0) of
std_logic_vector(7 downto 0);
signal sd_card_data_as : sd_card_data_a;

What I can do now is create an alias for a single element of the
signal:

alias data_start_block_s : std_logic_vector(7 downto 0) is
sd_card_data_as(0);

What I can NOT do is defining an alias that spans several elements of
the array:

alias data_stuff_bytes_s : std_logic_vector(15 downto 0) is
sd_card_data_as(10 downto 9);

Even when I define a type for the alias:

type data_stuff_bytes_a is array (514 downto 513) of
std_logic_vector(7 downto 0);
alias data_stuff_bytes_s : data_stuff_bytes_a is sd_card_data_as(2
downto 1);

My questions are:
Did anybody understand my promblem?
Can anybody present a solution?

Greetings,

/h
 
J

Jonathan Bromley

type sd_card_data_a is array (natural range 527 downto 0) of
std_logic_vector(7 downto 0);
signal sd_card_data_as : sd_card_data_a;

What I can do now is create an alias for a single element of the
signal:

alias data_start_block_s : std_logic_vector(7 downto 0) is
sd_card_data_as(0);

What I can NOT do is defining an alias that spans several elements of
the array:

alias data_stuff_bytes_s : std_logic_vector(15 downto 0) is
sd_card_data_as(10 downto 9);

No, you can't - your alias must be an array of the same
element types as were in the original array.
Even when I define a type for the alias:

type data_stuff_bytes_a is array (514 downto 513) of
std_logic_vector(7 downto 0);
alias data_stuff_bytes_s : data_stuff_bytes_a is sd_card_data_as(2
downto 1);

Different problem here. The alias must have the same
base type as the real object, I think. So you would
need something like this...

--- This one is just to reduce finger strain:
subtype byte is std_logic_vector(7 downto 0);

--- Generalised array type
type byte_array_t is array(natural) of byte;

--- Specialise it for your card_data array:
signal sd_card_data_as: byte_array_t(527 downto 0);

--- Now make your alias:
alias data_stuff: byte_array_t(514 downto 513)
is sd_card_data_as(2 downto 1);

I *think* that will work.... no time to check.
Can anybody present a solution?

You will probably find it easier to write functions
and procedures to access groups of elements of the
array. For example, to read and write several
adjacent elements as if they were
a single wide vector:

function get_Nbytes(data: byte_array_t;
first_adrs: natural;
num_bytes: positive)
return std_logic_vector is
variable result:
std_logic_vector(8*num_bytes-1 downto 0);
begin
for i in 0 to num_bytes-1 loop
result(8*i+7 downto 8*i) := data(first_adrs+i);
--- puts first address into rightmost 8 bits
end loop;
return result;
end function;

The matching "put" procedure is left as an exercise...
 
H

hhanff

No, you can't - your alias must be an array of the same
element types as were in the original array.



Different problem here.  The alias must have the same
base type as the real object, I think.  So you would
need something like this...

  --- This one is just to reduce finger strain:
  subtype byte is std_logic_vector(7 downto 0);

  --- Generalised array type
  type byte_array_t is array(natural) of byte;

  --- Specialise it for your card_data array:
  signal sd_card_data_as: byte_array_t(527 downto 0);

  --- Now make your alias:
  alias data_stuff: byte_array_t(514 downto 513)
                    is sd_card_data_as(2 downto 1);

I *think* that will work.... no time to check.


You will probably find it easier to write functions
and procedures to access groups of elements of the
array.  For example, to read and write several
adjacent elements as if they were
a single wide vector:

  function get_Nbytes(data: byte_array_t;
                      first_adrs: natural;
                      num_bytes: positive)
               return std_logic_vector is
    variable result:
         std_logic_vector(8*num_bytes-1 downto 0);
  begin
    for i in 0 to num_bytes-1 loop
      result(8*i+7 downto 8*i) := data(first_adrs+i);
      --- puts first address into rightmost 8 bits
    end loop;
    return result;
  end function;

The matching "put" procedure is left as an exercise...

Dear Jonathan!

Thanks for your quick reply. You were right in all points. I
implemented your advises today and exerything is fine now.
The solution to your exercise ahould be:

function put_Nbytes_f(data : std_logic_vector;
first_adrs : natural;
num_bytes : positive)
return byte_array_t is
variable result : byte_array_t(512 -1 downto 0);
begin
for i in 0 to num_bytes-1 loop
result(first_adrs+i) := data(8*i+7 downto 8*i);
--- puts 8 bit into rightmost rightmos byte
end loop;
return result(num_bytes-1 downto 0);
end function;

end package body sd_card_spi_wrapper_pack;


Yours,

/h
 
J

Jonathan Bromley

The solution to your exercise ahould be:

function put_Nbytes_f(data : std_logic_vector;
first_adrs : natural;
num_bytes : positive)
return byte_array_t is
variable result : byte_array_t(512 -1 downto 0);
begin
for i in 0 to num_bytes-1 loop
result(first_adrs+i) := data(8*i+7 downto 8*i);
--- puts 8 bit into rightmost rightmos byte
end loop;
return result(num_bytes-1 downto 0);
end function;

Yes, but that's probably a little inefficient - it
constructs the whole of "result" even if you use
only a tiny part of it. More important, though,
it has unnecessary arguments.

As an example, consider

mySig: byte_array_t(511 downto 0);
...
--- now we update just 2 words of it
mySig(5 downto 4) <= put_Nbytes(some_data, 4, 2);

Note how you are tempted to repeat the "start address"
on both sides. Indeed, the '4' argument to put_Nbytes
doesn't really do anything useful at all, and the '2'
length argument is unnecessary too. You could
mightily simplify it...

function to_bytes(data:std_logic_vector)
return byte_array_t is
constant nBytes: integer := data'length/8;
variable result: byte_array_t(nBytes-1 downto 0);
constant normalised:
std_logic_vector(data'length-1 downto 0)
:= data;
begin
assert (data'length mod 8) = 0
report "Data should be a multiple of 8 bits"
severity error;
for i in 0 to nBytes-1 loop
result(i) := data(8*i+7 downto 8*i);
end loop;
return result;
end;

Now you could do
mySig(5 downto 4) <= to_bytes(X"CAFE");
mySig(13 downto 10) <= to_bytes(X"BAD4F00D");

Originally I was thinking, rather, of passing
the target array as an out or inout argument to
a procedure, so that it is passed by reference,
and then having the procedure update just the
necessary elements. However, this is less
convenient than the function because you need
two versions of the procedure - one to update
a signal result, and one to update a variable [*].
And you can't call any procedure from within
a function [**]. So, on balance, I like the function
version better.

[*] VHDL wishlist item: Some way of overloading
subprograms based on the class (signal vs other things)
of their arguments, so that you can write identical
procedures to update signals and variables. Today
you must create two procedures with different names.

[**] Another VHDL wishlist item: void functions to
encapsulate non-time-consuming activity whilst
permitting input, output and inout arguments.
Did that make it into VHDL-2008? I don't think so.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top