verilogvivado

Vivado bi-directional INOUT signal on non-top-module


I've recently started working with bi-directional data transfer.

I wrote a simple Verilog module that takes an input in one clock cycle and returns a processed result (by adding one) after the bus turnaround.

module my_main_module(
    input sys_clock,
    inout [7:0] data_io
    );
    
    reg data_dir = 0; // 0: input, 1: output
    reg [7:0] data_reg;
    assign data_io = (data_dir) ? data_reg : 8'bz;
    
    reg [1:0] state = 0;
    always @(posedge sys_clock) begin
        case(state)
            0: begin // read data
                state <= 1;
                data_reg <= data_io + 1;
            end
            1: begin // bus turnaround
                state <= 2;
            end
            2: begin // write result
                state <= 3;
                data_dir <= 1; // set output
            end
            3: begin // bus turnaround
                state <= 0;
                data_dir <= 0; // tri-state, ready for next input
            end
        endcase
    end
endmodule

Simulated Module

Synthesis Expected

When using this module as the top module, everything works fine and the synthesised result is as expected.

However, when I try to use the Block Design editor, my bi-directional INOUT pins are not correctly forwarded.

Block Design Simple

Synthesis Failed

It seems like the tri-state flag is never forwarded.

I also get this warning on all data pins

HPDR #1 Warning
Hierarchical port(pin) data_io[0] direction INOUT is not consistent with the directions of the cell pins/ports found at that level of the netlist hierarchy.
Please review the design and consider changing the port(pin) direction. Both drivers and loads were expected for the net (data_io[0]) connected to this Port, but both were not found.

I searched online and found that the Utility Buffer IP provides an explicit IOBUF implementation.

Block Design Explicit

What makes this IP work correctly, while my module does not?


Solution

  • In all cases some sort of IO primitive (IOBUF/IBUF/OBUF/etc.) is required. If you don't explicitly instantiate one, the synthesis tool will infer one. In the case of your Verilog code, it can infer the IOBUF properly. However the block design tool isn't designed to do that and doesn't generate code that allows the synthesis tool to infer an IOBUF, so you have to instantiate one manually with the utility buffer block.