Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Best way to get an array of vectors into a vector?

56 views
Skip to first unread message

Carl

unread,
May 9, 2012, 9:03:21 AM5/9/12
to
Hi everyone,

I want to do this: I have an array of unsigned, say (7..0, 7..0, 7..0)
- in the example below I call this signal regDO, where the width and
the number of unsigned's in the array is determined by constant or
generics, and I want to turn this into a concatenated unsigned (in
this case (23..0)) - in the example below called outRegDI.

I did it with the process statement below. Is there any nicer way to
do it, since what I want to accomplish is fairly simple? It's since I
want it all to be fully parameterized that I find no better way to do
this.

(just to be clear - the code could be more compactly written, with
fewer constants etc., I know, that's not the issue - the issue is if
there is a better strategy than to loop thrugh the unsigned's in the
vectors and calculate the bit positions, then filling in to the
resulting vector.)

And yes, I do want regDO to be an *array* to start with, not e.g.
unsigned (23..0) - then the problem would be already solved. regDO is
used with units within generate-statement and then keeping them in an
array is the neat way to do it.

I have synthesized it with Xilinx XST and it synthesizes fine and the
input array is mapped to the output unsigned the way I want.

In the example below, the lowest array index of regDO is to be mapped
to the MSB side of outRegDI.

This is the code:

-- declarations:
constant inWidth: integer := 8;
constant outWidth: integer := 8*3;
constant ratio: integer := outWidth/inWidth;
constant nRegs: integer := ratio;
type TregData is array(0 to nRegs-1) of unsigned(inWidth-1 downto 0);
signal regDO: TregData;
signal outRegDI: unsigned (outwidth-1 downto 0)

-- code:
process(regDO) is
constant maxRegNo: integer := nRegs-1;
variable curInvertedRegIndex: integer range 0 to nRegs-1;
variable i: integer range 0 to nRegs-1;
variable curFromBit, curDowntoBit: integer range outWidth-1 downto
0;
begin
for i in 0 to nRegs-1 loop
-- when i goes from e.g. 0 to 7, curInvertedRegIndex goes from 7 to
0 - MSB bits are in
-- reg0 but should be placed at the highest bit indicies of
outRegDI.
curInvertedRegIndex := maxRegNo-i; -- e.g. 7-0=7, 7-1=6 ..., 7-7=0
curFromBit := (curInvertedRegIndex+1)*inWidth-1; -- eg. 8*8-1,
7*8-1, ... 1*8-1
curDowntoBit := (curInvertedRegIndex )*inWidth ;
end loop;
end process;



Here is the same code, here in a way so that it can be simulated or
synthesized right away:



library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all; -- signed, unsigned as array of std_logic

package miscPkg2 is

constant inWidth: integer := 8;
constant outWidth: integer := 8*3;

constant ratio: integer := outWidth/inWidth;
constant nRegs: integer := ratio;

type TregData is array(0 to nRegs-1) of unsigned(inWidth-1 downto 0);

end package miscPkg2;



library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all; -- signed, unsigned as array of std_logic

library work;
use work.miscPkg2.all;

entity test is
port(
regDO: in TregData;
outRegDI: out unsigned (outwidth-1 downto 0)
);
end entity;

architecture arch of test is
begin

process(regDO) is
constant maxRegNo: integer := nRegs-1;
variable curInvertedRegIndex: integer range 0 to nRegs-1;
variable i: integer range 0 to nRegs-1;
variable curFromBit, curDowntoBit: integer range outWidth-1 downto
0;
begin
for i in 0 to nRegs-1 loop
-- when i goes from e.g. 0 to 7, curInvertedRegIndex goes from 7 to
0 - MSB bits are in
-- reg0 but should be placed at the highest bit indicies of
outRegDI.
curInvertedRegIndex := maxRegNo-i; -- e.g. 7-0=7, 7-1=6 ..., 7-7=0
curFromBit := (curInvertedRegIndex+1)*inWidth-1; -- eg. 8*8-1,
7*8-1, ... 1*8-1
curDowntoBit := (curInvertedRegIndex )*inWidth ;
outRegDI(curFromBit downto curDowntoBit) <= regDO(i);
end loop;
end process;

end arch;

Andy

unread,
May 9, 2012, 9:31:25 AM5/9/12
to
Do you think you will use this conversion only once?

If not, write a function to do it, and put it in the package that
defines the array type. Define an unconstrained array of unsigned(7
downto 0) type, then have the function accept that type as an argument
and return an unsigned (unconstrained) that matches the the
concatenated size of the argument. Let the function interrogate the
argument and declare a variable that is the matching size, then
transfer the contents to the variable and return it. Make TregData a
(constrained?) subtype of the unconstrained master type (byte_vector
in the example below).

function to_unsigned(arg : byte_vector) return unsigned;

For portability it is usually best to normalize the argument's range
in a variable, in case someone calls it with a funky range (do not
assume it will always be called with an arg'range of (arg'length-1
downto 0). )

variable narg: byte_vector(arg'length - 1 downto 0)) := arg; -- range-
normalized arg

Then your architecture is reduced to a simple concurrent assignment:

outRegDI <= to_unsigned(RegDO);

Andy

Carl

unread,
May 13, 2012, 2:40:10 PM5/13/12
to
I agree Andy - making this into a function makes the code cleaner and
is preferred if I would use this more than once.

Andy

unread,
May 15, 2012, 8:59:35 AM5/15/12
to
On May 13, 1:40 pm, Carl <carw...@gmail.com> wrote:
> I agree Andy - making this into a function makes the code cleaner and
> is preferred if I would use this more than once.

Carl,

I would encourage you and others to think about what "use this code
more than once" means...

Anyone reviewing the code? Anyone maintaining the code? In this
context, "anyone" can be even be you, 6 weeks, 6 months or 6 years
after you wrote it. For myself, I could include "6 days" too!

Clean code is easier to understand for everyone. Good comments help,
but well written code, with appropriately named entities, functions,
procedures, variables, and signals, helps a lot more.

For example byte_vector may be too general a name in some cases. Is
the byte vector organized as little endian or big endian? Are both
kinds used in the same environment? perhaps big_endian and/or
little_endian are better names for the type. The to_unsigned()
function could be overridden for each type appropriately. And
naturally, to_big_endian(), etc. written as well.

Something to think about...

OK, I'm stepping off my soapbox now...

Andy
0 new messages