Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   VHDL (http://www.velocityreviews.com/forums/f18-vhdl.html)
-   -   Correct way of writing a mux followed by a register (http://www.velocityreviews.com/forums/t641952-correct-way-of-writing-a-mux-followed-by-a-register.html)

Chris Maryan 10-31-2008 05:00 PM

Correct way of writing a mux followed by a register
 
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


Mike Treseler 10-31-2008 07:48 PM

Re: Correct way of writing a mux followed by a register
 
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

Chris Maryan 10-31-2008 08:20 PM

Re: Correct way of writing a mux followed by a register
 
On Oct 31, 3:48*pm, Mike Treseler <mtrese...@gmail.com> 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/miketresel...unt_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

Mike Treseler 10-31-2008 09:07 PM

Re: Correct way of writing a mux followed by a register
 
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;
--------------------------------------------------

KJ 10-31-2008 10:44 PM

Re: Correct way of writing a mux followed by a register
 

"Chris Maryan" <kmaryan@gmail.com> wrote in message
news:b2ff3ece-781d-4b71-aebd-04fc4a2203ca@c2g2000pra.googlegroups.com...

> 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



sandeep 11-03-2008 11:30 AM

Re: Correct way of writing a mux followed by a register
 
On Nov 1, 6:44*am, "KJ" <kkjenni...@sbcglobal.net> wrote:
> "Chris Maryan" <kmar...@gmail.com> wrote in message
>
> news:b2ff3ece-781d-4b71-aebd-04fc4a2203ca@c2g2000pra.googlegroups.com...
>
>
>
>
>
> > 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.





Chris Maryan 11-03-2008 02:08 PM

Re: Correct way of writing a mux followed by a register
 
On Nov 3, 6:30*am, sandeep <sandeepkumar....@gmail.com> wrote:
> On Nov 1, 6:44*am, "KJ" <kkjenni...@sbcglobal.net> wrote:
>
>
>
>
>
> > "Chris Maryan" <kmar...@gmail.com> wrote in message

>
> >news:b2ff3ece-781d-4b71-aebd-04fc4a2203ca@c2g2000pra.googlegroups.com...

>
> > > 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

Mike Treseler 11-03-2008 02:33 PM

Re: Correct way of writing a mux followed by a register
 
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

KJ 11-03-2008 04:34 PM

Re: Correct way of writing a mux followed by a register
 
On Nov 3, 9:08*am, Chris Maryan <kmar...@gmail.com> 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

kennheinrich@sympatico.ca 11-03-2008 04:54 PM

Re: Correct way of writing a mux followed by a register
 
On Nov 3, 11:34*am, KJ <kkjenni...@sbcglobal.net> wrote:
> On Nov 3, 9:08*am, Chris Maryan <kmar...@gmail.com> 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;




All times are GMT. The time now is 07:22 PM.

Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57