Search code examples
verilogmux

change verilog 16x4 unidirectional mux to bidirectional mux


I wrote the following code to implement four 16:4 muxes:

module coder(
    selCh0, selCh1, selCh2, selCh3, 
    outCh0, outCh1, outCh2, outCh3,
    inEnc0, inEnc1, inEnc2, inEnc3
);
    input  wire [1:0] selCh0, selCh1, selCh2, selCh3;
    output wire [3:0] outCh0, outCh1, outCh2, outCh3;
    input  wire [3:0] inEnc0, inEnc1, inEnc2, inEnc3;

    mux_16x4 ch0(selCh0, inEnc0, inEnc1, inEnc2, inEnc3, outCh0);
    mux_16x4 ch1(selCh1, inEnc0, inEnc1, inEnc2, inEnc3, outCh1);
    mux_16x4 ch2(selCh2, inEnc0, inEnc1, inEnc2, inEnc3, outCh2);
    mux_16x4 ch3(selCh3, inEnc0, inEnc1, inEnc2, inEnc3, outCh3);
endmodule

module mux_16x4(sel, enc0, enc1, enc2, enc3, out);
    input wire [1:0] sel;
    input wire [3:0] enc0, enc1, enc2, enc3;
    output reg [3:0] out;

    always @(sel, enc0, enc1, enc2, enc3)
    begin
        case ({sel})
            2'b00: out <= enc0;
            2'b01: out <= enc1;
            2'b10: out <= enc2;
            2'b11: out <= enc3;
            default: out <= 4'b0;
        endcase;
    end
endmodule

My question is twofold:

  1. Is there a more efficient and/or better way to do this? I'm learning, so I don't have any particular issues with the code I wrote, but I thought I'd check to see if it could be improved.
  2. I need to reverse the fourth bit of each 4:1 mux. Right now, every bit in each inEncN bus is an input and every bit in each outChY bus is an output. I wrote it this way at first to see if it would work, but the real hardware needs a signal to go the other way.

To try to be more concise, I'll explain with a particular set of signals. Right now, the bits in outCh0[3:0] are all outputs. I really need outCh0[3] to be an input and for it to map to whichever inEncN[3] bus is selected by the select signals. Therefore, I also need all of the inEncN[3] signals to be outputs instead of inputs like the other three bits in each respective bus.

I tried to make all of the buses in question inout instead of input or output, but I couldn't get that to compile regardless of what I tried.

The code shown above compiles to 32 logic elements, which leaves eight spares. Fitting the code in 40 or less logic elements would be a huge win, but I have an acceptable plan B.

Any help would be greatly appreciated.


Solution

  • You don't need any bidirectional signals here, you just need to redefine your ports a bit. With system verilog you could pass multidimensional arrays as ports which would make this code a bit more compact. You could also create structs to contain the 3 inputs and 1 output in one object. However, this is a verilog question so we will do it that way:

    module coder(
      selCh0, selCh1, selCh2, selCh3, 
      outCh0, outCh1, outCh2, outCh3,
      inCh0, inCh1, inCh2, inCh3,
      inEnc0, inEnc1, inEnc2, inEnc3,
      outEnc0, outEnc1, outEnc2, outEnc3      
    );
      input  [1:0] selCh0, selCh1, selCh2, selCh3;
    
      input  [2:0] inEnc0, inEnc1, inEnc2, inEnc3;
      output       outEnc0, outEnc1, outEnc2, outEnc3;
    
      output [2:0] outCh0, outCh1, outCh2, outCh3;
      input        inCh0, inCh1, inCh2, inCh3;
    
      wire [2:0] inEnc [0:3];
      wire       inCh [0:3];
    
      assign inEnc[0] = inEnc0;
      assign inEnc[1] = inEnc1;
      assign inEnc[2] = inEnc2;
      assign inEnc[3] = inEnc3;
    
      assign inCh[0] = inCh0;
      assign inCh[1] = inCh1;
      assign inCh[2] = inCh2;
      assign inCh[3] = inCh3;
    
      assign outCh0 = inEnc[selCh0];
      assign outCh1 = inEnc[selCh1];
      assign outCh2 = inEnc[selCh2];
      assign outCh3 = inEnc[selCh3];
    
      assign outEnc0 = inCh[selCh0];
      assign outEnc1 = inCh[selCh1];
      assign outEnc2 = inCh[selCh2];
      assign outEnc3 = inCh[selCh3];
    
    endmodule
    

    Here is it repeated with arrays as ports in system verilog. This is also parameterized for flexibility in # of channels. Since the number of channels might not be a power of 2, we have to check that selCh is a legal value. If not, assign a default value to the outputs. The $clog2 function is used to calculate the minimum number of bits needed to select from NUMCH inputs:

    module coder #(parameter NUMCH=4) (
      input [$clog2(NUMCH)-1:0] selCh[NUMCH],
    
      input      [2:0] inEnc[NUMCH],
      output reg       outEnc[NUMCH],
    
      output reg [2:0] outCh[NUMCH],
      input            inCh[NUMCH]
      );
    
      always_comb begin
        for (int i=0; i<NUMCH; i++) begin
          if(selCh[i]<NUMCH) begin
            outCh[i] = inEnc[selCh[i]];
            outEnc[i] = inCh[selCh[i]];
          end
          else begin
            outCh[i] = '0;
            outEnc[i] = '0;
          end
        end
      end
    endmodule