Mux good coding style

B

Bil Bob

Guest
Hi all,
I'm trying to find the better way to describe a simple mux in Verilog.
for now let's consider 4-1 mux (with 16b, meaning 16 muxes), so we
have (as I see it) 2 options:
1.
wire [15:0] out_bus;
wire [1:0] ctrl;
wire [15:0] bus0;
wire [15:0] bus1;
wire [15:0] bus2;
wire [15:0] bus3;
assign out_bus = ctrl == 2'd0 ? bus0 :
ctrl == 2'd1 ? bus1 :
ctrl == 2'd2 ? bus2 : bus3;

2.
reg [15:0] out_bus;
wire [1:0] ctrl;
wire [15:0] bus0;
wire [15:0] bus1;
wire [15:0] bus2;
wire [15:0] bus3;
always @*
begin
case (ctrl)
2'd0 : out_bus = bus0 ;
2'd1 : out_bus = bus1 ;
2'd2 : out_bus = bus2 ;
2'd3 : out_bus = bus3 ;
endcase


both seem to in order, but... option 1 is simulator friendly, but
some synthesis tools might generate priority encoder (I know the
synopsys tools our backend guys are using did), even if one is not
needed. option 2 is sysnthesis friendly, but simulation, when ctrl
changes to 'X', out_bus preserves it's value.

I'm trying to understand how this 'simple' design should be written in
order for simulation and synthesis tools to understand the same

thanks in advance
 
On 2009-02-25, Bil Bob <ibilbob@gmail.com> wrote:
both seem to in order, but... option 1 is simulator friendly, but
some synthesis tools might generate priority encoder (I know the
synopsys tools our backend guys are using did), even if one is not
needed. option 2 is sysnthesis friendly, but simulation, when ctrl
changes to 'X', out_bus preserves it's value.
I'm usually using one of two versions:

Either a default case instead of the last case. In your example, I would
use default: instead of 2'd3:.

Another way is to simply add a default case which sets the output to
x if the input is not an expected value. (If you believe that it is good
that X values propagate in your simulation.)


/Andreas
 
Bil Bob wrote:
I'm trying to find the better way to describe a simple mux in Verilog.
for now let's consider 4-1 mux (with 16b, meaning 16 muxes), so we
have (as I see it) 2 options:

assign out_bus = ctrl == 2'd0 ? bus0 :
ctrl == 2'd1 ? bus1 :
ctrl == 2'd2 ? bus2 :
bus3;

always @*
case (ctrl)
2'd0 : out_bus = bus0 ;
2'd1 : out_bus = bus1 ;
2'd2 : out_bus = bus2 ;
2'd3 : out_bus = bus3 ;
endcase

both seem to in order, but... option 1 is simulator friendly, but
some synthesis tools might generate priority encoder (I know the
synopsys tools our backend guys are using did),
Interesting - I believe the case statement infers the same priority - except
that in this instance all the cases are orthogonal so that means nothing
(also true of the continuous assignment). I guess this comes down to which
idioms the synthesis tool recognises.

even if one is not
needed. option 2 is sysnthesis friendly, but simulation, when ctrl
changes to 'X', out_bus preserves it's value.
The solution to this (as has already been pointed out) is to add:
default : out_bus = 16'hxxxx;
to your case statement. I would normally chose the case statement for
readability. There is also a third option:

assign out_bus = ({16{ctrl==2'h0}} & bus0) |
({16{ctrl==2'h1}} & bus1) |
({16{ctrl==2'h2}} & bus2) |
({16{ctrl==2'h3}} & bus3);

Which I think is more readable than using the ternary operator, but is more
explicit than the case statement. It is particularly useful (in conjunction
with the appropriate assertion) if the control signal is already one-hot
encoded.

Actually, you could also write it using ternary operators as a tree:

assign out_bus = ctrl[1]? (ctrl[0]? bus3
: bus2)
: (ctrl[0]? bus1
: bus0);

This is less readable still (imho) and certainly not scalable, but does not
imply a priority tree.

John

--
John Penton, posting as an individual unless specifically indicated
otherwise.
 
On Feb 25, 8:58 am, "John Penton" <john.pen...@arm.com> wrote:
Bil Bob wrote:
I'm trying to find the better way to describe a simple mux in Verilog.
for now let's consider 4-1 mux (with 16b, meaning 16 muxes), so we
have (as I see it) 2 options:
assign out_bus = ctrl == 2'd0 ? bus0 :
                 ctrl == 2'd1 ? bus1 :
                 ctrl == 2'd2 ? bus2 :

                                  bus3;

always @*
  case (ctrl)
    2'd0 : out_bus = bus0 ;
    2'd1 : out_bus = bus1 ;
    2'd2 : out_bus = bus2 ;
    2'd3 : out_bus = bus3 ;
  endcase
both seem to in order, but...  option 1 is simulator friendly, but
some synthesis tools might generate priority encoder (I know the
synopsys tools our backend guys are using did),

Interesting - I believe the case statement infers the same priority - except
that in this instance all the cases are orthogonal so that means nothing
(also true of the continuous assignment).  I guess this comes down to which
idioms the synthesis tool recognises.

even if one is not
needed. option 2 is sysnthesis friendly, but simulation, when ctrl
changes to 'X', out_bus preserves it's value.

The solution to this (as has already been pointed out) is to add:
    default : out_bus = 16'hxxxx;
to your case statement.  I would normally chose the case statement for
readability.  There is also a third option:

assign out_bus = ({16{ctrl==2'h0}} & bus0) |
                 ({16{ctrl==2'h1}} & bus1) |
                 ({16{ctrl==2'h2}} & bus2) |
                 ({16{ctrl==2'h3}} & bus3);

Which I think is more readable than using the ternary operator, but is more
explicit than the case statement.  It is particularly useful (in conjunction
with the appropriate assertion) if the control signal is already one-hot
encoded.

Actually, you could also write it using ternary operators as a tree:

assign out_bus = ctrl[1]? (ctrl[0]? bus3
                                  : bus2)
                        : (ctrl[0]? bus1
                                  : bus0);

This is less readable still (imho) and certainly not scalable, but does not
imply a priority tree.

John

--
John Penton, posting as an individual unless specifically indicated
otherwise.
You can force the synthesis not to use priority encoding
by adding "// synthesis parallel_case" to the case
statement. However it seems to me that even if the
tool started to create a priority encoder, after
logic optimization you should end up with the
same results given the orthogonal case statement.

Regards,
Gabo
 
On Feb 26, 12:00 pm, Uwe Bonnes <b...@elektron.ikp.physik.tu-
darmstadt.de> wrote:
Bil Bob <ibil...@gmail.com> wrote:
Hi all,
I'm trying to find the better way to describe a simple mux in Verilog.
for now let's consider 4-1 mux (with 16b, meaning 16 muxes), so we
have (as I see it) 2 options:
1.
wire [15:0] out_bus;
wire [1:0] ctrl;
wire [15:0] bus0;
wire [15:0] bus1;
wire [15:0] bus2;
wire [15:0] bus3;
assign out_bus =        ctrl == 2'd0 ? bus0 :
                                ctrl == 2'd1 ? bus1 :
                                ctrl == 2'd2 ? bus2 : bus3;
2.
reg [15:0] out_bus;
wire [1:0] ctrl;
wire [15:0] bus0;
wire [15:0] bus1;
wire [15:0] bus2;
wire [15:0] bus3;
always @*
begin
  case (ctrl)
        2'd0 : out_bus = bus0 ;
        2'd1 : out_bus = bus1 ;
        2'd2 : out_bus = bus2 ;
        2'd3 : out_bus = bus3 ;
  endcase
both seem to in order, but...  option 1 is simulator friendly, but
some synthesis tools might generate priority encoder (I know the
synopsys tools our backend guys are using did), even if one is not
needed. option 2 is sysnthesis friendly, but simulation, when ctrl
changes to 'X', out_bus preserves it's value.
I'm trying to understand how this 'simple' design should be written in
order for simulation and synthesis tools to understand the same

What about
wire [15:0] out_bus;
wire [15:0] out_data[0:3];
wire [1:0] ctrl;
wire [15:0] bus0;
wire [15:0] bus1;
wire [15:0] bus2;
wire [15:0] bus3;

assign out_data[0] = bus0;
assign out_data[1] = bus1;
assign out_data[2] = bus2;
assign out_data[3] = bus3;

assign out_bus = out_data[ctrl];

--
Uwe Bonnes                b...@elektron.ikp.physik.tu-darmstadt.de

Institut fuer Kernphysik  Schlossgartenstrasse 9  64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------

this is a good idea for a full case implementation, but it doesn't
answer the partial case issue

thanks
 
On Feb 26, 1:16 am, Bil Bob <ibil...@gmail.com> wrote:
Thanks all for taking the time to reply and supply some insights...

To broaden the issue here:
Consider a case where I have a 10b bus, and I want to control a simple
mux:
assign out = bus == 10'h1  ? in1 :
             bus == 10'h2  ? in2 :
             bus == 10'h12 ? in3 :
             bus == 10'h31 ? in4 : in5;

Writing it like this will propagate any 'X' in the simulation on
'bus', and give me in the simulation the needed result. On the other
hand, it might produce a priority encoder, which is not needed here,
in the synthesis process.
I can code it with case like this:
always @*
begin
  case (bus)
    10'h1   : out = in1;
    10'h2   : out = in2;
    10'h12  : out = in3;
    10'h31  : out = in4;
    default : out = in5;
  endcase
end

Doing so will produce the needed synthesis outcome, but in the
simulation I'm losing the 'x' propagation. I can't really describe
every option just to have the 'x' at the default...
I'm not really trying to solve a specific coding problem, but rather
address a more general issue the way our tools look at muxes and
priority encoders.

Thanks
Did you check this in simulation? The
two forms should be exactly equivalent.
 
On Feb 26, 3:40 pm, gabor <ga...@alacron.com> wrote:
On Feb 26, 1:16 am, Bil Bob <ibil...@gmail.com> wrote:





Thanks all for taking the time to reply and supply some insights...

To broaden the issue here:
Consider a case where I have a 10b bus, and I want to control a simple
mux:
assign out = bus == 10'h1  ? in1 :
             bus == 10'h2  ? in2 :
             bus == 10'h12 ? in3 :
             bus == 10'h31 ? in4 : in5;

Writing it like this will propagate any 'X' in the simulation on
'bus', and give me in the simulation the needed result. On the other
hand, it might produce a priority encoder, which is not needed here,
in the synthesis process.
I can code it with case like this:
always @*
begin
  case (bus)
    10'h1   : out = in1;
    10'h2   : out = in2;
    10'h12  : out = in3;
    10'h31  : out = in4;
    default : out = in5;
  endcase
end

Doing so will produce the needed synthesis outcome, but in the
simulation I'm losing the 'x' propagation. I can't really describe
every option just to have the 'x' at the default...
I'm not really trying to solve a specific coding problem, but rather
address a more general issue the way our tools look at muxes and
priority encoders.

Thanks

Did you check this in simulation?  The
two forms should be exactly equivalent.- Hide quoted text -

- Show quoted text -
when you change the value from any value to all 'x', the assign output
changes to 'x' as well, but the case output preserves the last value,
or changes to the default if you talking about the last example
 
On Feb 27, 9:38 am, Bil Bob <ibil...@gmail.com> wrote:
On Feb 26, 3:40 pm, gabor <ga...@alacron.com> wrote:



On Feb 26, 1:16 am, Bil Bob <ibil...@gmail.com> wrote:

Thanks all for taking the time to reply and supply some insights...

To broaden the issue here:
Consider a case where I have a 10b bus, and I want to control a simple
mux:
assign out = bus == 10'h1  ? in1 :
             bus == 10'h2  ? in2 :
             bus == 10'h12 ? in3 :
             bus == 10'h31 ? in4 : in5;

Writing it like this will propagate any 'X' in the simulation on
'bus', and give me in the simulation the needed result. On the other
hand, it might produce a priority encoder, which is not needed here,
in the synthesis process.
I can code it with case like this:
always @*
begin
  case (bus)
    10'h1   : out = in1;
    10'h2   : out = in2;
    10'h12  : out = in3;
    10'h31  : out = in4;
    default : out = in5;
  endcase
end

Doing so will produce the needed synthesis outcome, but in the
simulation I'm losing the 'x' propagation. I can't really describe
every option just to have the 'x' at the default...
I'm not really trying to solve a specific coding problem, but rather
address a more general issue the way our tools look at muxes and
priority encoders.

Thanks

Did you check this in simulation?  The
two forms should be exactly equivalent.- Hide quoted text -

- Show quoted text -

when you change the value from any value to all 'x', the assign output
changes to 'x' as well, but the case output preserves the last value,
or changes to the default if you talking about the last example
You cannot predict how synthesizer generates your mux. So it is quite
pointless to think of all these 'X' cases.
 
On Feb 26, 5:38 pm, Bil Bob <ibil...@gmail.com> wrote:
On Feb 26, 3:40 pm, gabor <ga...@alacron.com> wrote:



On Feb 26, 1:16 am, Bil Bob <ibil...@gmail.com> wrote:

Thanks all for taking the time to reply and supply some insights...

To broaden the issue here:
Consider a case where I have a 10b bus, and I want to control a simple
mux:
assign out = bus == 10'h1  ? in1 :
             bus == 10'h2  ? in2 :
             bus == 10'h12 ? in3 :
             bus == 10'h31 ? in4 : in5;

Writing it like this will propagate any 'X' in the simulation on
'bus', and give me in the simulation the needed result. On the other
hand, it might produce a priority encoder, which is not needed here,
in the synthesis process.
I can code it with case like this:
always @*
begin
  case (bus)
    10'h1   : out = in1;
    10'h2   : out = in2;
    10'h12  : out = in3;
    10'h31  : out = in4;
    default : out = in5;
  endcase
end

Doing so will produce the needed synthesis outcome, but in the
simulation I'm losing the 'x' propagation. I can't really describe
every option just to have the 'x' at the default...
I'm not really trying to solve a specific coding problem, but rather
address a more general issue the way our tools look at muxes and
priority encoders.

Thanks

Did you check this in simulation?  The
two forms should be exactly equivalent.- Hide quoted text -

- Show quoted text -

when you change the value from any value to all 'x', the assign output
changes to 'x' as well, but the case output preserves the last value,
or changes to the default if you talking about the last example
O.K., to be sure, I simulated this and you are right.

To make the two statements exactly equivalent you need to
change the assignments to

assign out = bus === 10'h1 ? in1 :
bus === 10'h2 ? in2 :
bus === 10'h12 ? in3 :
bus === 10'h31 ? in4 : in5;

Then you have the same simulation behavior as the case statement.

I guess I was under the impression that a case statement treated
X as unknown and would therefore pass the X through. Apparently
it treats X as neither 0 nor 1, thereby falling into the default
case. "casex" behaves differently yet, treating X as either 0
or 1 as needed to fill the match condition, therefore taking the
first case whose non-X bits match. I don't see an easy way
for a case statement to match your original assignment. Essentially
you would need to cover all cases of 1's and 0's and then have
a default case assigning out to X.

Regards,
Gabor
 
On Wed, 25 Feb 2009 06:31:41 -0800 (PST)
gabor <gabor@alacron.com> wrote:

You can force the synthesis not to use priority encoding
by adding "// synthesis parallel_case" to the case
statement. However it seems to me that even if the
tool started to create a priority encoder, after
logic optimization you should end up with the
same results given the orthogonal case statement.
I wouldn't recommend doing that. The case statement as written is
parallel, since all 4 cases are mutually exclusive. You don't need to
add "parallel_case". The only time that parallel_case should be used is
in one-hot decoding case statements where it's not clear that the
statements are parallel when indeed they are.


--
Thank goodness modern convenience is a thing of the remote future.
-- Pogo, by Walt Kelly
 
Thanks all for taking the time to reply and supply some insights...

To broaden the issue here:
Consider a case where I have a 10b bus, and I want to control a simple
mux:
assign out = bus == 10'h1 ? in1 :
bus == 10'h2 ? in2 :
bus == 10'h12 ? in3 :
bus == 10'h31 ? in4 : in5;

Writing it like this will propagate any 'X' in the simulation on
'bus', and give me in the simulation the needed result. On the other
hand, it might produce a priority encoder, which is not needed here,
in the synthesis process.
I can code it with case like this:
always @*
begin
case (bus)
10'h1 : out = in1;
10'h2 : out = in2;
10'h12 : out = in3;
10'h31 : out = in4;
default : out = in5;
endcase
end

Doing so will produce the needed synthesis outcome, but in the
simulation I'm losing the 'x' propagation. I can't really describe
every option just to have the 'x' at the default...
I'm not really trying to solve a specific coding problem, but rather
address a more general issue the way our tools look at muxes and
priority encoders.

Thanks
 
Bil Bob <ibilbob@gmail.com> wrote:
Hi all,
I'm trying to find the better way to describe a simple mux in Verilog.
for now let's consider 4-1 mux (with 16b, meaning 16 muxes), so we
have (as I see it) 2 options:
1.
wire [15:0] out_bus;
wire [1:0] ctrl;
wire [15:0] bus0;
wire [15:0] bus1;
wire [15:0] bus2;
wire [15:0] bus3;
assign out_bus = ctrl == 2'd0 ? bus0 :
ctrl == 2'd1 ? bus1 :
ctrl == 2'd2 ? bus2 : bus3;

2.
reg [15:0] out_bus;
wire [1:0] ctrl;
wire [15:0] bus0;
wire [15:0] bus1;
wire [15:0] bus2;
wire [15:0] bus3;
always @*
begin
case (ctrl)
2'd0 : out_bus = bus0 ;
2'd1 : out_bus = bus1 ;
2'd2 : out_bus = bus2 ;
2'd3 : out_bus = bus3 ;
endcase

both seem to in order, but... option 1 is simulator friendly, but
some synthesis tools might generate priority encoder (I know the
synopsys tools our backend guys are using did), even if one is not
needed. option 2 is sysnthesis friendly, but simulation, when ctrl
changes to 'X', out_bus preserves it's value.

I'm trying to understand how this 'simple' design should be written in
order for simulation and synthesis tools to understand the same
What about
wire [15:0] out_bus;
wire [15:0] out_data[0:3];
wire [1:0] ctrl;
wire [15:0] bus0;
wire [15:0] bus1;
wire [15:0] bus2;
wire [15:0] bus3;

assign out_data[0] = bus0;
assign out_data[1] = bus1;
assign out_data[2] = bus2;
assign out_data[3] = bus3;

assign out_bus = out_data[ctrl];

--
Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de

Institut fuer Kernphysik Schlossgartenstrasse 9 64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------
 

Welcome to EDABoard.com

Sponsor

Back
Top