Correct way of writing a mux followed by a register

C

Chris Maryan

I've googled around but haven't seen a good generic and flexible way
of writing a mux followed by a synchronous output. I've come up with
code that's correctly interpreted as a mux by synplify, but it's a bit
sketchy. Can anyone please enlighten me as to the right way of doing
this:

The following seems to be accepted by synplify as a mux followed by a
register, but it seems logically incorrect:

constant : width := 16;
signal wr_en : std_logic;
signal addr : std_logic_vector(addr_width downto 0);
signal addr_int : integer;
....
addr_int <= conv_integer(addr);

mux_and_reg : process (clk)
begin
if rising_edge(clk) then
if wr_en ='1' then
for i in 0 to log2(addr_width) loop
if i = addr_int then
data_out <= data_in((i+1)*width-1 downto i*width);
end if;
end loop;
end if;
end if;
end process;

I would expect the loop to get unrolled and something weird to happen
relating to the assignment (something like catching only the last
value of i).

Plan B was to do this:

mux_and_reg : process (clk)
begin
if rising_edge(clk) then
if wr_en ='1' then
data_out <= data_in((addr_int+1)*width-1 downto addr_int*width);
end if;
end if;
end process;

But this seems to infer shift registers, which makes sense.

So what is the right way to get a mux followed by a register? All of
the standard examples focus on a hard coded address width and a select
statement. How do I do this with a flexible for-loop or for-generate?

Thanks,

Chris
 
M

Mike Treseler

Chris said:
I've googled around but haven't seen a good generic and flexible way
of writing a mux followed by a synchronous output. I've come up with
code that's correctly interpreted as a mux by synplify, but it's a bit
sketchy. Can anyone please enlighten me as to the right way of doing
this

Start with something specific and inflexible to get started.

An if/then/else statement inside a synchronous process
can infer a mux and a register. The question
is, will this netlist in my head really do what I want?

The process of trial and error synthesis
is the long road to working code, especially
if the full design is more than a mux and a register.
It may work fine for simple cases,
but only if I already know the correct answer in advance.

I test and debug my code using simulation
until all the waves and assertions works as I expect.
Then, I usually run an rtl view in synthesis
to see the logical schematic of the full entity
and to check my design rules.
The following seems to be accepted by synplify as a mux followed by a
register, but it seems logically incorrect:

So run a sim and find out for sure.

-- Mike Treseler

related examples:
http://mysite.verizon.net/miketreseler/count_enable.pdf
http://mysite.verizon.net/miketreseler/count_enable.vhd
 
C

Chris Maryan

Start with something specific and inflexible to get started.

An if/then/else statement inside a synchronous process
can infer a mux and a register. The question
is, will this netlist in my head really do what I want?

The process of trial and error synthesis
is the long road to working code, especially
if the full design is more than a mux and a register.
It may work fine for simple cases,
but only if I already know the correct answer in advance.

I test and debug my code using simulation
until all the waves and assertions works as I expect.
Then, I usually run an rtl view in synthesis
to see the logical schematic of the full entity
and to check my design rules.


So run a sim and find out for sure.

    -- Mike Treseler

related examples:http://mysite.verizon.net/miketrese...ite.verizon.net/miketreseler/count_enable.vhd

Thanks Mike. Actually, yes it simulates correctly, it just disagreed
with my understanding of how for-> if works, which I suppose is the
clarification I was looking for.

My expectation looking at the code was that the loop would unroll to
something like
for ... loop
if ... then
... code for i=0;
end if;
if ... then
... code for i = 1;
end if;
...
end loop;

rather than:

for ... loop
if ... then
... code for i=0;
elsif ... then
... code for i = 1;
elsif ...
...
end if;
end loop;

Which seems to be what it actually unrolls to.

Chris
 
M

Mike Treseler

Chris said:
Thanks Mike. Actually, yes it simulates correctly, it just disagreed
with my understanding of how for-> if works, which I suppose is the
clarification I was looking for.

Yes, it was confusing,
and in those cases, I either run a sim to figure it out,
or, if I have time, pull a function out so I can read it.
Like you said, it's sort of like n byte shifts per clock.

I use my own 'push' function for things like this.

-- Mike Treseler

--------------------------------------------------
function sel (
choice : boolean;
a, b : std_logic_vector) -- sel(false,a,b) = a
return std_logic_vector is -- like the C lang: sel ? a:b
begin
if choice then return a; else return b; end if;
end function sel;
--------------------------------------------------
function push (slim : in std_logic_vector;
wide : in std_logic_vector;
left : in boolean := true)
return std_logic_vector is
-- push byte into word from left or right
subtype slim_t is std_logic_vector(slim'length-1 downto 0);
subtype wide_t is std_logic_vector(wide'length-1 downto 0);
variable in_vec : slim_t := slim;
variable out_vec : wide_t := wide;
begin
return(sel(
choice => left,
a => out_vec(out_vec'left - in_vec'length
downto 0) & in_vec,
b => in_vec & out_vec(out_vec'left
downto in_vec'length))
);
end function push;
--------------------------------------------------
 
K

KJ

Thanks Mike. Actually, yes it simulates correctly, it just disagreed
with my understanding of how for-> if works, which I suppose is the
clarification I was looking for.

My expectation looking at the code was that the loop would unroll to
something like
for ... loop
if ... then
... code for i=0;
end if;
if ... then
... code for i = 1;
end if;
...
end loop;

rather than:

for ... loop
if ... then
... code for i=0;
elsif ... then
... code for i = 1;
elsif ...
...
end if;
end loop;

Generally speaking a sequential series of if statements is the form for a
priority encoder, and that is logically equivalent to the single
if/elsif/elsif.../end if statement so really the two forms that you listed
are logically identical.

I'm guessing though that what you're trying to get across is that this could
be implemented without the long nested if/else logic being generated in the
synthesized design much like a decoder decodes addresses. To do that though
one needs to have mutually exclusive conditions (which you do; i=0, i=1...)
and describe the design in a way that the tool understands that they are
mutually exclusive. While a smart synthesizer possibly 'could' see that the
various 'if' conditions are actually all mutually exclusive, as you've found
you can't count on that to occur. If you know some set of conditions are
mutually exclusive, then you will be able to express that with a case
statement. When you do so, you'll find that the logic does synthesize to
what I think you were expecting.

The converse of that is that if you can not express it as a case statement
then the conditions are not reeeeeeeally mutually exclusive in spite of what
you think you 'know' to be true.

Kevin Jennings
 
S

sandeep

Generally speaking a sequential series of if statements is the form for a
priority encoder, and that is logically equivalent to the single
if/elsif/elsif.../end if statement so really the two forms that you listed
are logically identical.

I'm guessing though that what you're trying to get across is that this could
be implemented without the long nested if/else logic being generated in the
synthesized design much like a decoder decodes addresses.  To do that though
one needs to have mutually exclusive conditions (which you do; i=0, i=1...)
and describe the design in a way that the tool understands that they are
mutually exclusive.  While a smart synthesizer possibly 'could' see that the
various 'if' conditions are actually all mutually exclusive, as you've found
you can't count on that to occur.  If you know some set of conditions are
mutually exclusive, then you will be able to express that with a case
statement.  When you do so, you'll find that the logic does synthesize to
what I think you were expecting.

The converse of that is that if you can not express it as a case statement
then the conditions are not reeeeeeeally mutually exclusive in spite of what
you think you 'know' to be true.

Kevin Jennings- Hide quoted text -

- Show quoted text -

Hi
"for i in 0 to log2(addr_width) loop "
Above line is should be
for i in 0 to 2**(addr_width) loop
for logically correct of functionality.
Whatever you are trying to write it, it will infer priority encoder.
I think simply using case statement for parallel mux should be fine.
 
C

Chris Maryan

Hi
"for i in 0 to log2(addr_width) loop "
Above line is should be
for i in 0 to 2**(addr_width) loop
for logically correct of functionality.
Whatever you are trying to write it, it will infer priority encoder.
I think simply using case statement for parallel mux should be fine.- Hide quoted text -

- Show quoted text -

Yes, that should have been 2**..., Careless typing on my part.

Your comment brings to mind a question:
- Can a case statement be used somehow with a for loop? (the key thing
here is the generic driven dimensions of the mux)

Despite all the examples of using generics for signal widths, etc.
There's a shortage of examples out there of generating size-flexible
structures. I'd love to see good examples of using loops for a generic
sized mux, demux, encoder and decoder (both priority and perhaps more
importantly, non-priority). Does anyone know of any good references
that show this? Anyone care to share some easy to read code?

Thanks,

Chris
 
K

KJ

I'd love to see good examples of using loops for a generic
sized mux, demux, encoder and decoder (both priority and perhaps more
importantly, non-priority). Does anyone know of any good references
that show this? Anyone care to share some easy to read code?

I wouldn't use a loop for a mux. Instead I'd use the following which
can be used as either a concurrent statement or inside a process.

mux_out <= mux_data_in(to_integer(unsigned(mux_sel)));

For a demux,
for i in demux_out'range loop
if (to_integer(unsigned(demux_sel)) = i) then
demux_out(i) <= demux_in;
else
demux_out(i) <= (others => '0');
end if;
end loop;

KJ
 
K

kennheinrich

I wouldn't use a loop for a mux.  Instead I'd use the following which
can be used as either a concurrent statement or inside a process.

mux_out <= mux_data_in(to_integer(unsigned(mux_sel)));

For a demux,
for i in demux_out'range loop
  if (to_integer(unsigned(demux_sel)) = i) then
    demux_out(i) <= demux_in;
  else
    demux_out(i) <= (others => '0');
  end if;
end loop;

KJ

Inside a process, how about just the shorter form (skipping the
looping and the testing):

demux_out <= (others => (others => '0'));
demux_out(to_integer(unsigned(demux_sel)) <= demux_in;

If the demux is a single bit, skip the nested others choice. Fully
worked example below.

- Kenn

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

package types is
subtype byte is std_logic_vector(7 downto 0);
type byte_array is array(integer range <>) of byte;
end types;

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.types.all;

entity demux is

port (
demux_in : in byte;
demux_sel: in std_logic_vector(3 downto 0);
demux_out: out byte_array(0 to 15)
);

end demux;

architecture a of demux is

begin -- a

process(demux_in, demux_sel)
begin
demux_out <= (others => (others => '0'));
demux_out(to_integer(unsigned(demux_sel))) <= demux_in;
end process;

end a;
 
A

Andy

This assumes that the range of values represented by demux_sel is
within the range of positions in demux_out. Using a loop and an "if i
= demux_sel then" is required if demux_sel is larger than the index
range for demux_out.

Most synthesis tools will infer that multiple static (in a synthesis
way, including loop indices) "equal to" comparisons to the same vector/
integer are mutually exclusive. Thus the priority logic falls out
anyway, though it may not be apparent in the "rtl" view. I have even
added exit statements and reordered the loop to speed up simulation
with no effect on synthesis. I normally use Synplify.

The parallel if statements and the nested if-elsif statement are
functionally equivalent only if executed in the reverse order of
indexing.

Andy
 
C

Chris Maryan

I wouldn't use a loop for a mux.  Instead I'd use the following which
can be used as either a concurrent statement or inside a process.

mux_out <= mux_data_in(to_integer(unsigned(mux_sel)));

Actually, this statement is what sparked my interest in this to begin
with. I was originally using something similar, but Synplify didn't
synthesize it as I would have expected. Admitedly, I haven't tried to
use this as just a combinatorial statement, but in a process the
following code:

process (clk)
begin
if rising_edge(sys) then
if wr_en = '1' then
data_out <= data_in((i+1)*DATA_WIDTH-1 downto i*DATA_WIDTH);
end if;
end if;
end process;

generates something like a shift register (some combination of LSH in
the RTL viewer, presumably shifting the input vector by a multiple of
i). The code below turns out ok:

process (clk)
begin
if rising_edge(clk) then
if wr_en = '1' then
for i in 0 to MAX_NUM-1 loop
if i = addr_int then
data_out <= data_in((i+1)*DATA_WIDTH-1 downto
i*DATA_WIDTH);
end if;
end loop;
end if;
end if;
end process;

The two pieces of code are functionally equivalent, but the difference
in resource utilization is about 2 to 1.

Chris
 
C

Chris Maryan

This assumes that the range of values represented by demux_sel is
within the range of positions in demux_out. Using a loop and an "if i
= demux_sel then" is required if demux_sel is larger than the index
range for demux_out.

Most synthesis tools will infer that multiple static (in a synthesis
way, including loop indices) "equal to" comparisons to the same vector/
integer are mutually exclusive. Thus the priority logic falls out
anyway, though it may not be apparent in the "rtl" view. I have even
added exit statements and reordered the loop to speed up simulation
with no effect on synthesis. I normally use Synplify.

The parallel if statements and the nested if-elsif statement are
functionally equivalent only if executed in the reverse order of
indexing.

Andy

Thanks for the useful insight on what synthesis tools will infer in
these cases, this is really enlightening.
 
C

Chris Maryan

That first code should have been:
process (clk)
begin
if rising_edge(sys) then
if wr_en = '1' then
data_out <= data_in((addr_int+1)*DATA_WIDTH-1 downto
addr_int*DATA_WIDTH);
end if;
end if;
end process;
 
C

Chris Maryan

Chris,
Your results are interesting.  I would (probably you too?) have
expected the first to do better than the 2nd.  Which version of
Synplify are you using?  There was a release out that did not do as
well as the others that I downloaded in the March 2008 time frame.
They replaced it in a short period of time, so if you were unlucky
this could be part of the issue.  Have you simulated the gate
results?  Do they both work?

What FPGA are you targeting?  Do you get the same 2x better for
case 2 with other technologies?

You may wish to try what KJ suggested as separating the Mux from
the register in this case may clear up its confusion.

Best,
Jim










- Show quoted text -

This is on Synplify 9.6, targeting a Virtex5 SX95, that resource count
is the LUT count out of the .srr file for the whole module (which is
dominated by this mux). I haven't tried anything else, since I have a
working version (the 2nd code). More than anything this has sparked my
curiosity since I'm realtively new to doing this stuff for a living
and am still learning how to get the tools to do what I want. Anyways,
if I get a chance, I'll play around with it and see what Synplify
comes up with for the variations people have discussed.
 

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,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top