7

I am trying to create a module which switches x input data packets to a single output packet according to a one-hot input.

If x was a fixed value of 4, I would just create a case statement,

case (onehot)
  4'b0001  : o_data = i_data[0];
  4'b0010  : o_data = i_data[1];
  4'b0100  : o_data = i_data[2];
  4'b1000  : o_data = i_data[3];
  default  : o_data = 'z;
endcase

But, with variable x, how do I define all cases?

5 Answers 5

13
parameter X = 4;  

input [X-1:0] onehot;
input i_data [X];
output reg o_data;

always_comb 
begin
   o_data = 'z;
   for(int i = 0; i < X; i++) begin
      if (onehot == (1 << i))
         o_data = i_data[i];
   end
end
Sign up to request clarification or add additional context in comments.

7 Comments

Yes, i did mean that thanks, I will edit the q. Two questions though Why does the line o_data = 'z not clash with o_data = i_data[i]; and is the line if(oneshot == (1 << i)) equivalent to if(oneshot[i] == 1)?
The assignment before the for loop acts like a default value. The last assignment should win. The two comparisons are not equivalent since oneshot[i] == 1 will match based only on that one bit. If multiple bits are high then you get multiple matches.
For example, if oneshot == 4'b1001 then oneshot[0] == 1 will be true but oneshot == (1<<0) will be false.
Ok thanks I got the first q. With the second, does the (1 << i) ensure only one match? Could you explain in words what it means or what it is called so I can look it up?! Thanks again.
The << does a left bit shift, so 4'b0001<<0 is 4'b0001, 4'b0001<<1 is 4'b0010, etc...
|
11

If you can assert that onehot is truly one-hot or 0, then you could use a generate

package mytypes;
typedef logic [7:0] packet_t;
endpackage 

module mux #(int X) (
      input logic [X-1:0] onehot,
      input mytypes::packet_t i_data[X],
      output wire mytypes::packet_t o_data
      );
for(genvar i=0;i<X;i++) begin
   assign o_data = onehot[i] ? i_data[i] : 'z;
end
endmodule

1 Comment

I've used this technique before with the Xilinx tools, but now that I use the Altera ones I get a warning that internal tristate buffers aren't allowed. I'll probably do a check of the schematic to see how it gets implemented, but on the off chance, do you know if this technique still will work with the Altera tools?
4

Here's a fully parameterized synthesizable mux optimized for a one-hot input (i.e. no priority encoding) using an OR tree. Note that the output is driven to 0 instead of 'z' if no input is enabled:

module mux
 #( parameter int unsigned inputs = 4,
    parameter int unsigned width = 8 )
  ( output logic [width-1:0] out,
    input logic sel[inputs],
    input logic [width-1:0] in[inputs] );

    always_comb
    begin
        out = {width{1'b0}};
        for (int unsigned index = 0; index < inputs; index++)
        begin
            out |= {width{sel[index]}} & in[index];
        end
    end
endmodule

Comments

0
  1. Define unpacked arrays of input-to-output signals
  2. Assign each input interface's input-to-output signals to the unpacked arrays using generate-for block
  3. Assign arr[sel] to output interface's input-to-output signals
  4. Connect the output-to-input signals using generate-for block

An example of parameterized Block RAM Interface Mux:

module bram_mux #(
    parameter int NUM_PORTS = 2,
    parameter int ADDR_W = 10,
    parameter int DATA_W = 176*8
) (
    input wire [$clog2(NUM_PORTS) - 1 : 0] sel,
    bram_intf.ram i_bram_intf_in [NUM_PORTS],
    bram_intf.dut i_bram_intf_out
);

genvar i;

logic we_arr [NUM_PORTS];
logic re_arr [NUM_PORTS];
logic [ADDR_W - 1 : 0] addr_arr [NUM_PORTS];
logic [DATA_W - 1 : 0] data_arr [NUM_PORTS];

generate
    for (i = 0; i < NUM_PORTS; i++) begin: blk_bram_mux
        assign we_arr[i] = i_bram_intf_in[i].we;
        assign re_arr[i] = i_bram_intf_in[i].re;
        assign addr_arr[i] = i_bram_intf_in[i].addr;
        assign data_arr[i] = i_bram_intf_in[i].data;
        assign i_bram_intf_in[i].q = i_bram_intf_out.q;
    end
endgenerate

assign i_bram_intf_out.addr = addr_arr[sel];
assign i_bram_intf_out.data = data_arr[sel];
assign i_bram_intf_out.we = we_arr[sel];
assign i_bram_intf_out.re = re_arr[sel];

endmodule

Module above can be synthesized in Quartus and works correctly on Altera FPGA.

Comments

-1

I think 'wor' datatype is the real savior here. Please find an example code:

module cnt64_shared
   #(
   parameter INSTANCES          = 6 // Number of shared istances
   )
(
    input        [INSTANCES-1:0][31:0]  in_L_f      , // i - input
    input        [INSTANCES-1:0]        in_sel_1hot , // i - input selection        

        // clk and reset - add new signals before   
   input                        clk                     , // i - clock
   input                        rst_n                     // i - reset

);

    wor [31:0]  in_L_mux; 

    genvar i;
        
generate
    for (i=0;i<INSTANCES;i=i+1) begin
        assign in_L_mux = in_sel_1hot[i]    ?   in_L_f[i]   :   32'h0   ;  
    end
endgenerate

endmodule

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.