Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
16 years ago

verilog- parameterized mux

For the life of me I cannot figure out how to generate a parameterized mux in verilog...

I understand how to generate, say, a 4:1 MUX of "N" bits wide... But I am trying to generate an N:1 mux, of only 1 bit wide.

I've been scouring the googleweb for weeks with no such luck (aside from hit after hit for a variable-width mux)...

Have I stumbled upon something impossible?

thanks,

..dane

7 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I hope I'm not doing your homework for you. One of the shortcomings of Verilog is the inability to generate ports. So you have to bring the input in as a bus.

    I haven't compiled this so there may be errors:

    module mux (#parameter  WIDTH           = 8,
               # parameter  CHANNELS        = 4) (
        input         in_bus,
        input       sel,   
        output                   out
        );
    genvar ig;
        
    wire     input_array ;
    assign  out = input_array;
    generate
        for(ig=0; ig<CHANNELS; ig=ig+1) begin: array_assignments
            assign  input_array = in_bus;
        end
    endgenerate
    //define the clogb2 function
    function integer clogb2;
      input depth;
      integer i,result;
      begin
        for (i = 0; 2 ** i < depth; i = i + 1)
          result = i + 1;
        clogb2 = result;
      end
    endfunction
    endmodule
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    I hope I'm not doing your homework for you. One of the shortcomings of Verilog is the inability to generate ports. So you have to bring the input in as a bus.

    --- Quote End ---

    Hahaha.. no, you're not doing your homework for me. Truth be told it's a project I've been working on for a customer for about three months, and this is the last piece to the puzzle (the rest of the project is all done and working just fine) that I just can't seem to crack.

    I will admit to only a few years of experience with verilog, so your code snippet has a few curiosities in it that I'll ask below.

    
    genvar ig;
        
    wire     input_array +:CHANNELS-1];
    assign  out = input_array;
    generate
        for(ig=0; ig<CHANNELS; ig=ig+1) begin: array_assignments
            assign  input_array = in_bus+:WIDTH];
        end
    endgenerate
    

    I am not familiar with a "+" in the port width. A very quick google indicates maybe it's a polarity indicator, but that doesn't help me much -- can you explain what you're accomplishing by including it and how it would behave if it were excluded?

    I see what you're doing with your generate statement now, and feel a bit silly for not thinking of that myself. I was trying to go about it a much different (and obviously more difficult) way...

    I will mess around with your code snip and report back how it goes..

    thanks again,

    ..dane
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    1 - That first "+" sign in the array declaration is a typo. See I told you there might be errors.

    :).

    2 - The second "+:" sign in the "assign" statement is legitimate and is called a "Variable Vector Part Select" operator.

    For example, a statement like:

    assign data1 = data[8+:8]

    is equivalent to:

    assign data1 = data[15:8];

    Generically:

    assign data1 = data[x+:y]

    So the "+:" operator uses "x" as the starting index of the vector and uses "y" to determine how many bits of the vector to index. The "+:" operator adds "y" bits to "x" while the "-:" operand subtracts "y" bits from "x".

    Jake

    I will post some equivalent examples shortly.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Equivalent / alternative examples

    1 - The one I already posted with a correction:

    module mux (#parameter  WIDTH           = 8,
               # parameter  CHANNELS        = 4) (
        input         in_bus,
        input       sel,   
        output                   out
        );
    genvar ig;
        
    wire     input_array ;
    assign  out = input_array;
    generate
        for(ig=0; ig<CHANNELS; ig=ig+1) begin: array_assignments
            assign  input_array = in_bus;
        end
    endgenerate
    //define the clogb2 function
    function integer clogb2;
      input depth;
      integer i,result;
      begin
        for (i = 0; 2 ** i < depth; i = i + 1)
          result = i + 1;
        clogb2 = result;
      end
    endfunction
    endmodule

    2 - Similar to# 1 but without using the "Variable Vector Part Select" operator:

    module mux (#parameter  WIDTH           = 8,
               # parameter  CHANNELS        = 4) (
        input         in_bus,
        input       sel,   
        output                   out
        );
    genvar ig;
        
    wire     input_array ;
    assign  out = input_array;
    generate
        for(ig=0; ig<CHANNELS; ig=ig+1) begin: array_assignments
            assign  input_array = in_bus;
        end
    endgenerate
    //define the clogb2 function
    function integer clogb2;
      input depth;
      integer i,result;
      begin
        for (i = 0; 2 ** i < depth; i = i + 1)
          result = i + 1;
        clogb2 = result;
      end
    endfunction
    endmodule

    3 - Equivalent logic without using a generate statement. I don't recommend this because some simulators don't work well with the "reg" type declaration for the array. Again, you could rewrite this to not use the "+:" operator if you wish.

    module module mux (#parameter  WIDTH           = 8,
               # parameter  CHANNELS        = 4) (
        input         in_bus,
        input       sel,   
        output                   out
        );
    integer i;
        
    reg      input_array ;
    assign  out = input_array;
    always @*
        for(i=0; i<CHANNELS; i=i+1)
            input_array = in_bus;
    //define the clogb2 function
    function integer clogb2;
      input depth;
      integer i,result;
      begin
        for (i = 0; 2 ** i < depth; i = i + 1)
          result = i + 1;
        clogb2 = result;
      end
    endfunction
    endmodule
    

    Jake
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks again Jake for your help.. While cleaning up some of the project I found an optimization opportunity that greatly simplified the problem and made the mux much simpler. I really do appreciate your help though, I've learned a great deal from this thread!

    thank you!

    ..dane
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Old post, but wondering if this ever synthesized? For me, Quartus synthesis errors out on the line:

    input [clogb2(CHANNELS-1)-1:0] sel,

    Stating:

    Error (10140): Verilog HDL error at param_mux.sv(6): range index is not constant

    (I just added another parameter for SEL_WIDTH, and used that, forcing the user to manually enter this value. It's easy enough to do, but not ideal...)
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Rysc,

    jakobjones suggested:

    
    module mux (#parameter  WIDTH           = 8,
               # parameter  CHANNELS        = 4) (
        input         in_bus,
        input       sel,   
        output                   out
        );
    

    but I am implementing slightly differently. To continue jakobjones' example it would be:

    
    module mux 
    (
    in_bus,
    sel,
    out
    );
    parameter WIDTH = 8;
    parameter CHANNELS = 4;
    input  in_bus;
    input  sel;
    output  out;
    //define the clogb2 function
    function integer clogb2;
      input depth;
      integer i,result;
      begin
        for (i = 0; 2 ** i < depth; i = i + 1)
          result = i + 1;
        clogb2 = result;
      end
    endfunction
    

    I haven't actually tried to synthesize jakobjones' example, so I cannot comment on its ability to be synthesized. However, my structure above which separates the port list declaration and their width definitions does synthesize. I will report however that I've been in the Xilinx world lately so I cannot comment on how the Quartus tools respond to the above example.

    good luck, and let us know how it goes.

    ..dane