Correct way of writing a mux followed by a register

Discussion in 'VHDL' started by Chris Maryan, Oct 31, 2008.

  1. Chris Maryan

    Chris Maryan Guest

    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
    Chris Maryan, Oct 31, 2008
    #1
    1. Advertising

  2. Chris Maryan wrote:
    > 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
    Mike Treseler, Oct 31, 2008
    #2
    1. Advertising

  3. Chris Maryan

    Chris Maryan Guest

    On Oct 31, 3:48 pm, Mike Treseler <> wrote:
    > Chris Maryan wrote:
    > > 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/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
    Chris Maryan, Oct 31, 2008
    #3
  4. Chris Maryan wrote:

    > 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;
    --------------------------------------------------
    Mike Treseler, Oct 31, 2008
    #4
  5. Chris Maryan

    KJ Guest

    "Chris Maryan" <> wrote in message
    news:...

    > 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
    KJ, Oct 31, 2008
    #5
  6. Chris Maryan

    sandeep Guest

    On Nov 1, 6:44 am, "KJ" <> wrote:
    > "Chris Maryan" <> wrote in message
    >
    > news:...
    >
    >
    >
    >
    >
    > > 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- 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.
    sandeep, Nov 3, 2008
    #6
  7. Chris Maryan

    Chris Maryan Guest

    On Nov 3, 6:30 am, sandeep <> wrote:
    > On Nov 1, 6:44 am, "KJ" <> wrote:
    >
    >
    >
    >
    >
    > > "Chris Maryan" <> wrote in message

    >
    > >news:...

    >
    > > > 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- 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.- 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
    Chris Maryan, Nov 3, 2008
    #7
  8. Chris Maryan wrote:

    > Despite all the examples of using generics for signal widths, etc.
    > There's a shortage of examples out there of generating size-flexible
    > structures.


    The trick is to not only declare the dimensions,
    but subtypes that use those dimensions and registers
    that use those subtypes, like this:

    http://mysite.verizon.net/miketreseler/stack.vhd

    -- Mike Treseler
    Mike Treseler, Nov 3, 2008
    #8
  9. Chris Maryan

    KJ Guest

    On Nov 3, 9:08 am, Chris Maryan <> wrote:
    >
    > 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
    KJ, Nov 3, 2008
    #9
  10. Chris Maryan

    Guest

    On Nov 3, 11:34 am, KJ <> wrote:
    > On Nov 3, 9:08 am, Chris Maryan <> wrote:
    >
    >
    >
    > > 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


    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;
    , Nov 3, 2008
    #10
  11. Chris Maryan

    Andy Guest

    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
    Andy, Nov 3, 2008
    #11
  12. Chris Maryan

    Chris Maryan Guest

    On Nov 3, 11:34 am, KJ <> wrote:

    > 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
    Chris Maryan, Nov 3, 2008
    #12
  13. Chris Maryan

    Chris Maryan Guest

    On Nov 3, 1:12 pm, Andy <> wrote:
    > 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.
    Chris Maryan, Nov 3, 2008
    #13
  14. Chris Maryan

    Chris Maryan Guest

    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;
    Chris Maryan, Nov 3, 2008
    #14
  15. Chris Maryan

    Chris Maryan Guest

    On Nov 3, 1:49 pm, Jim Lewis <> wrote:
    > 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
    >
    >
    >
    > > On Nov 3, 11:34 am, KJ <> wrote:

    >
    > >> 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- Hide quoted text -

    >
    > - 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.
    Chris Maryan, Nov 3, 2008
    #15
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Fano
    Replies:
    0
    Views:
    1,013
  2. salman sheikh

    Best way to mux addresses

    salman sheikh, Jan 30, 2004, in forum: VHDL
    Replies:
    0
    Views:
    512
    salman sheikh
    Jan 30, 2004
  3. Oleg
    Replies:
    1
    Views:
    713
    Francisco Rodriguez
    Feb 18, 2004
  4. Oleg
    Replies:
    4
    Views:
    6,768
    Ray Andraka
    Apr 6, 2004
  5. transformer
    Replies:
    1
    Views:
    2,771
    Lorenzo Di Gregorio
    Aug 2, 2004
Loading...

Share This Page