Recursive function to generate mux output

E

Edward Watts

Hi all,

I posted a short while ago about using generate statements to select
out sections of a parallel signal or to combine sections into a
parallel signal (serial-ish to parallel and parallel to serial-ish
converters)
http://groups.google.com/group/comp.lang.vhdl/browse_thread/thread/67501029fa8041c6

The input serial to parallel works fine, and is synthesised and
general.
The output parallel to serial syntactically is fine, but won't
synthesis:
I'm using Xilinx 7.1i Foundation, and the code is the following

output_g : for i in 0 to NumberOfOutputOperands-1
generate
outputSlice_g : for j in 0 to NumberOfOutputBitGroups-1
generate
outputSliceLast_g : if (j = NumberOfOutputBitGroups-1) and (i =
NumberOutputOperands-1)
generate
process(clk)
if rising_edge(clk) then
if RSTIn = '1' then
...reset code.
else
result_internal <= result(i)( (j+1)*OutputWidth - 1 downto
j*OutputWidth );
-- other IO stuff.
end if;
end if;
end process;
end generate;
-- similar generate for all other output slices.
end generate;
end generate;

And the problem with this code is that a synthesis error occurs:
multi-source in Unit ... on signal result_internal<...>

VHDL requires that the process statement be inside the generate
statement, and not the other way around. Is there an option to use
perhaps a block statement to replicate the behaviour.

I've now tried to create a mux tree structure with a function, which
crashed the synthesis tool.
Here's the function, based off a reduction operator:

There were two errors raised, one at line 0 of this file of "Overflow
in constant operation", and the other is pointed out in the source
code.

function mux_build ( arg: std_logic_vector, a : std_logic_vector )
return std_logic_vector is
variable Result, Upper, Lower : std_logic_vector( SizeOfOutputBus-1
downto 0 );
variable Half : integer;
variable internal : std_logic_vector( arg'length-1 downto 0 );
begin
internal := arg;
if ( internal'length = SizeOfOutputBus ) then
Result := internal;
else
Half := 2**(internal'length-1);
Upper := mux_build( internal( internal'left downto Half ), a );
--gives "Use of null array slice on signal <internal> is not supported"
Lower := mux_build( internal( Half-1 downto internal'right), a );
if ( a( internal'length-SizeOfOutputBus-1) = '1' ) then
Result := Upper;
else
Result := Lower;
end if;
end if;
return Result;
end function;

Can someone help me with the nitty gritty of the language? I haven't
had too much experience with functions and synthesis.

Thanks,
ed.
 
K

Kai Harrekilde-Petersen

Edward Watts said:
I've now tried to create a mux tree structure with a function, which
crashed the synthesis tool.
Here's the function, based off a reduction operator:

There were two errors raised, one at line 0 of this file of "Overflow
in constant operation", and the other is pointed out in the source
code.

function mux_build ( arg: std_logic_vector, a : std_logic_vector )
return std_logic_vector is
variable Result, Upper, Lower : std_logic_vector( SizeOfOutputBus-1
downto 0 );
variable Half : integer;
variable internal : std_logic_vector( arg'length-1 downto 0 );
begin
internal := arg;
if ( internal'length = SizeOfOutputBus ) then
Result := internal;
else
Half := 2**(internal'length-1);
Upper := mux_build( internal( internal'left downto Half ), a );
--gives "Use of null array slice on signal <internal> is not supported"
Lower := mux_build( internal( Half-1 downto internal'right), a );
if ( a( internal'length-SizeOfOutputBus-1) = '1' ) then
Result := Upper;
else
Result := Lower;
end if;
end if;
return Result;
end function;

Can someone help me with the nitty gritty of the language? I haven't
had too much experience with functions and synthesis.

You have left out what widths you are testing with, but my best guess,
is that the function barfs when you get down to 1 bit wide vectors (0
downto 0).

Say your input isn't a multiple of SizeOfOutputBus, then the
internal'length = SizeOfOutputBus test will never succeed, and you end
up trying to split a 1-bit bus in one of the halfs.

Regards,


Kai
 
M

Mike Treseler

Edward said:
And the problem with this code is that a synthesis error occurs:
multi-source in Unit ... on signal result_internal<...>

Generate loops tend to have problems at the edges.
Sometimes you need a process or two outside the loop.

I find vhdl simulation a very quick way to
debug problems like this.

I find that a single process design
style is a good way to *eliminate*
problems like this.


-- Mike Treseler
 
E

Edward Watts

Replying to both posts.

Mike Treseler helped out with:
I find that a single process design
style is a good way to *eliminate*
problems like this.

The issue is we don't want to retype out all the different multiples of
OutputBusWidth each time we change the size of the internal
representation (possibly up to 1024 bits). I'm not sure of a VHDL
pattern that deals with this problem, but i'm working on another
generate option. If I get it working, I'll post both the input and
output solutions for critique or dust-collecting :)

Kai Harrekilde-Petersen chipped in with:
Say your input isn't a multiple of SizeOfOutputBus, then the
internal'length = SizeOfOutputBus test will never succeed, and you end
up trying to split a 1-bit bus in one of the halfs.
So a guard condition on the 1-bit wide bus should help...
However the function assign will barf on the usage, since it should
always return a value of
 
E

Edward Watts

Replying to both posts.

Mike Treseler helped out with:
I find that a single process design
style is a good way to *eliminate*
problems like this.

The issue is we don't want to retype out all the different multiples of
OutputBusWidth each time we change the size of the internal
representation (possibly up to 1024 bits). I'm not sure of a VHDL
pattern that deals with this problem, but i'm working on another
generate option. If I get it working, I'll post both the input and
output solutions for critique or dust-collecting :)

Kai Harrekilde-Petersen chipped in with:
Say your input isn't a multiple of SizeOfOutputBus, then the
internal'length = SizeOfOutputBus test will never succeed, and you end
up trying to split a 1-bit bus in one of the halfs.

So a guard condition on the 1-bit wide bus should help the synthesis
tool.
The input to the function is always some multiple of SizeOfOutputBus,
but not necessarily 2^n * SizeOfOutputBus.
However the function assign will barf on the usage, if it returns a
1-bit wide answer, since it should always return a value of
SizeOfOutputBus wide. Is there a method of constraining the input sizes
using some sort of assertion or precondition (I know it's not Eiffel)
whereby I can indicate to the compiler what it can assume?

cheers,
ed.

PS sorry if this is a double post. I may have tapped the post button
accidentally
 
M

Mike Treseler

Edward said:
Mike Treseler helped out with:


The issue is we don't want to retype out all the different multiples of
OutputBusWidth each time we change the size of the internal
representation (possibly up to 1024 bits).

Understood. My point was that I would
apply the generic dimensions to a some complex data type
to cover the same design in a single process.
I would find this easier to sim and debug.

-- Mike Treseler
 
E

Edward Watts

Here's the solution to all my problems.
I was attempting to convert a std_logic_vector signal to an integer to
use as an index into the output signal. Xilinx told me that I couldn't
use to_integer (error was "to_integer cannot have such operands in this
context."). However using conv_integer worked fine.

So here it is:
OutputBitGroupCounter is std_logic_vector(OutputBitGroupCounterBits-1
downto 0)
resultIn is std_logic_vector(N_Bits-1 downto 0);
result_internal is std_logic_vector(SizeOfOutputBus-1 downto 0);
out_internal is array(OutputBitGroupCounter_MAX downto 0) of
std_logic_vector(SizeOfOutputBus-1 downto 0);
outputCounting is a flag that is set when outputs are being read

-- use a generate signal to clock the N bit wide internal signal into a
2D array
outputSelect_g : for i in OutputBitGroupCounter_MAX downto 0 generate
process(CLK)
begin
--clock inputs into each part of the array slice.
if rising_edge(CLK) then
if RST = '1' then
out_internal(i) <= (others => '0');
elsif expFinished = '1' then
out_internal(i) <= resultIn( (i+1)*SizeOfOutputBus-1 downto
i*SizeOfOutputBus);
end if;
end if;
end process;
end generate;

-- followed with the almost trivial:
process(CLK)
begin
if rising_edge(CLK) then
if RST = '1' then
result_internal <= (others => '0');
elsif outputCounting = '1' then
result_internal <= out_internal( conv_integer(
outputBitGroupCounter ) );
end if;
end if;
end process;

ed.
 

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,994
Messages
2,570,222
Members
46,810
Latest member
Kassie0918

Latest Threads

Top