verilogsystem-verilog

How to swap inout wires within a contained hierarchy (of which is synthesizable)?


For context, please look at my attached diagram to see what I am trying to accomplish.

Essentially, I want to swap inout wires using a contained hierarchy that will allow me to have more modular RTL in my design.

The problem is that it is difficult to do swapping of inout wires in SystemVerilog and the only way I found that was able to accomplish this led to a non-synthesizable error, despite it being the same functional behavior of doing it in a different, less modular way.

Adding minimum reproducible code below as requested - The code below does the expected swapping but using the alias command. I would like to accomplish similar behavior but without the alias command. Thank you.

mod_a.sv

module mod_a  (
    inout bit0,
    inout bit1,
    input signal_a,
    input [1:0] bus_a
);

wire mod_b_bit0;
wire mod_b_bit1;

mod_b u_mod_b (
    .bit0(mod_b_bit0),
    .bit1(mod_b_bit1),
    .signal_a(signal_a),
    .bus_a(bus_a)
);

mapper u_mapper (
    .mod_b_bit0(mod_b_bit0),
    .mod_b_bit1(mod_b_bit1),
    .bit0(bit0),
    .bit1(bit1)
);

endmodule

mod_b.sv

module mod_b  (
    inout bit0,
    inout bit1,
    input signal_a,
    input [1:0] bus_a
);

assign bit0 = signal_a ? 1'bZ : bus_a[0];
assign bit1 = signal_a ? 1'bZ : bus_a[1];

endmodule

mapper.sv

module mapper  (
    inout mod_b_bit0,
    inout mod_b_bit1,
    inout bit0,
    inout bit1
);

alias bit0 = mod_b_bit1; //swap
alias bit1 = mod_b_bit0; //swap

endmodule

tb.sv

module testbench_top;

   wire bit0;
   wire bit1;

   logic  signal_a;
   logic [1:0] bus_a;

   logic dq0_driver;
   logic dq1_driver;

   assign    bit0 = signal_a ? dq0_driver : 1'bZ;
   assign    bit1 = signal_a ? dq1_driver : 1'bZ;

initial begin
        signal_a = 0;
        dq0_driver = 0;
        dq1_driver = 0;
        bus_a = $random();

        #20 
        signal_a = 1;
        dq0_driver = 1;
        dq1_driver = 0;

        #20 
        signal_a = 0;
        bus_a = $random();

        #20 
        signal_a  = 1;
        dq0_driver = 0;
        dq1_driver = 1;

        #20 
        signal_a = 0;
        bus_a = $random();

        #20 
        signal_a  = 1;
        dq0_driver = 1;
        dq1_driver = 1;

        #20 
        signal_a = 0;
        bus_a = $random();

        #20 
        signal_a  = 1;
        dq0_driver = 0;
        dq1_driver = 0;

        #20 
        signal_a  = 1;
        dq0_driver = 1;
        dq1_driver = 0;

        #1000 $stop;
end

mod_a u_mod_a ( //mod A
    .bit0(bit0),
    .bit1(bit1),
    .signal_a(signal_a),
    .bus_a(bus_a)
);


endmodule

enter image description here


Solution

  • The resolution for this was shared by Greg in the comment of my post.

    2 potential solutions -

    Solution #1: Two implicitly named ports connected to same internal net (non-ANSI style module header)

    module submapper(
        bit0,
        bit0,
        bit1,
        bit1
    );
    
    inout bit0;
    inout bit1;
    
    endmodule
    
    module mapper  (
        inout mod_b_bit0,
        inout mod_b_bit1,
        inout bit0,
        inout bit1
    );
    
    submapper u_submapper(
        bit0,
        mod_b_bit1, //swap happens here
        bit1,
        mod_b_bit0 //swap happens here
    );
    
    endmodule
    

    Solution #2 (CLEANER): Two ports with different names connected to same internal net (non-ANSI style module header)

    module submapper2(
    .bit0(bit0), .mod_b_bit0(bit1), //swap happens here
    .bit1(bit1), .mod_b_bit1(bit0) //swap happens here
    );
    
    inout bit0;
    inout bit1;
    
    endmodule
    
    module mapper (
        inout mod_b_bit0,
        inout mod_b_bit1,
        inout bit0,
        inout bit1
    );
    
    submapper2 u_submapper2 (.*);  
    
    endmodule
    

    I have tested both and they can compile, elaborate, and synthesize without any errors. Thanks Greg.