Mux versus internal high impledance

Started by prashantpd 3 years ago5 replieslatest reply 3 years ago79 views


I have been an FPGA designer for more than a decade now and tutor a class on FPGA design at University presently. In all these years, I have had two ways of implementing a multiplexer functionality. 

The first one is the conventional

module mux (
    input [9:0] din,
    input [3:0] sel1,
    input [3:0] sel2,
    output dout

reg op1, op2;

always @(*)
    4'd0 : op1 = din[0];
    4'd1 : op1 = din[1];
    4'd2 : op1 = din[2];
    4'd3 : op1 = din[3];
    4'd4 : op1 = din[4];
    4'd5 : op1 = din[5];
    4'd6 : op1 = din[6];
    4'd7 : op1 = din[7];
    4'd8 : op1 = din[8];
    4'd9 : op1 = din[9];
    default op1 = 1'd0;

always @(*)
    4'd0 : op2 = din[0];
    4'd1 : op2 = din[1];
    4'd2 : op2 = din[2];
    4'd3 : op2 = din[3];
    4'd4 : op2 = din[4];
    4'd5 : op2 = din[5];
    4'd6 : op2 = din[6];
    4'd7 : op2 = din[7];
    4'd8 : op2 = din[8];
    4'd9 : op2 = din[9];
    default op2 = 1'd0;

assign dout = op1 ^ op2;


while the other one is a bit quirky and uses internal tri states. Now before you draw the big guns, I know FPGAs do not have internal tristates (the last ones which had them are probably Virtex II Pro, but I learned Verilog on a Virtex II Pro). The code follows.

module hiz #(
    parameter DW = 10,
    parameter SW = 4
    input [DW-1:0] din,
    input [SW-1:0] sel1,
    input [SW-1:0] sel2,
    output dout

reg op1, op2;

genvar i;
for (i=0;i<=DW-1;i=i+1)
begin : SEL1

    always @(*)
    if(sel1 == i)
        op1 = din[i];
        op1 = 1'bz;
    always @(*)
    if(sel2 == i)
        op2 = din[i];
        op2 = 1'bz;

assign dout = op1 ^ op2;


The advantage I saw of this code is that my module is parametrizable. In my experience, the design works correctly.

Any comments on the design style

[ - ]
Reply by rajkeerthy18May 4, 2018

Either ASIC/FPGA, Tristate is not permitted within the fabric. The only place to implement tristate are the IOs. Parameterisation is a matter of coding style, does not fit in the context of tristate. Mux has been implemented using for loops decades ago, must be conventional too. The synthesis tool just rolls out the loop and implements the correct structure. 

[ - ]
Reply by prashantpdMay 6, 2018

Hello Rajkeerthy18,

Thank you for your reply. 

However, I do not agree with your statement that either ASIC/FPGA do not permit Tristate within the fabric. As I have mentioned in my original post, in the Virtex II Pro FPGA, each CLB had access to an "internal" tri-state buffer (page 43). These were used to drive tristate buses inside the FPGA fabric. Yes they were not true tristates, but were implemented using AND-OR logic. The pseudo tri-states were a nice way to implement a bus-like functionality within modules inside the FPGA. 

Having said that however, I agree that whenever the the synthesis tool sees the generate for loop, it just rolls out and implements the correct structure.

I am wanting to know if there is a situation that can arise where the generate loop with the tristate will not work correctly.

[ - ]
Reply by rajkeerthy18May 6, 2018

In a tri-state the totem pole output transistors are not driven meaning they are off. If such a structure could be inferred from an HDL model then we are sure that tri-state is permitted inside the fabric. Then multiple drivers could exist for that signal. Mux structure achieves many to one driver and logically equivalent. The Virtex II pro internal tristate buffer emulated a tri-state, which is not exactly a tri-state logic. The AND-OR logic is a mux structure.

With generate statement one could generate any structure/instances including IOs which have tristate. A situation where a generate loop does not work correctly with tristate - I am curious to know the design intent because generate is an HDL statement to describe logic in a compact way, Whereas tristate is a logic state. Generate statement is not related to logic state. 

[ - ]
Reply by martinthompsonMay 4, 2018

I'm a VHDLer, but can you not do something like:

op1 = d[sel1]; op2=d[sel2]; dout = op1^op2;


I'd hope the synthesier would do just the same, but I don't have one to hand!

Or is the default case something critical?  In which case I would do

op1 <= d(sel1) when sel1 < 10 else 0;


Should also be perfectly parameterisable...

Perhaps I'm missing something (perhaps verilog-fu!)?

Regarding your question about design-style - I personally don't like using Zs to make muxes on principle - the principle being that I don't like to use design-patterns that are unlikely to be recognised, and I'm not sure many/most will, given that it is so long since tristate buses actually existed in the FPGA.  

But I think it's a personal preference thing!



[ - ]
Reply by prashantpdMay 6, 2018

Hello Martin,

Thank you for your reply. 

I agree with your design principle that it is inadvisable to use design patterns that are unlikely to be recognised. Will keep that in mind the next time I am writing code.