Showing results for 
Show  only  | Search instead for 
Did you mean: 
Registered: ‎10-05-2010

System Verilog Interface Simulation/Synthesis Mismatch

I am upgrading a legacy design from Spartan6 / Verilog to Artix7 / SystemVerilog, and I'm trying to use interfaces wherever I can to clean up the hierarchy.


The original design had several wide buses with status and commands. Within the modules, these buses were broken apart with part-select syntax, and I thought I could hide this in the interface definitions. I discovered that interfaces are working differently in simulation and synthesis. I am using Vivado 2017.3 on Windows.


Here is a simple test interface. A 32-bit masterStatus bus is divided into four 8-bit buses.


interface statusBus;
    logic [31:0]masterStatus;
    logic [7:0]stat0;
    logic [7:0]stat1;
    logic [7:0]stat2;
    logic [7:0]stat3;

    modport master (output masterStatus);

    modport slave (input .stat0(masterStatus[7:0]), .stat1(masterStatus[15:8]),
                            .stat2(masterStatus[23:16]), .stat3(masterStatus[31:24]));



Now let's define a top level module with a 32-bit status input and four 8-bit outputs:

module top (
    input [31:0]StatusIn,
    output [7:0]stat0Out,
    output [7:0]stat1Out,
    output [7:0]stat2Out,
    output [7:0]stat3Out


    // Instantiate a status bus
    statusBus topStatus();


    // Assign the masterStatus
    assign topStatus.masterStatus = StatusIn;


    // Pass this bus to a lower level where the bytes are unpacked and passed back
    test1 t1 (.stat(topStatus.slave), .*);

endmodule // top


Now the lower level of the hierarchy.


module test1 (
    statusBus stat,
    output [7:0]stat0Out,
    output [7:0]stat1Out,
    output [7:0]stat2Out,
    output [7:0]stat3Out);


    `ifdef simulation
        // This assignment works with simulation and gives the result I expected

        // stat.stat0 returns the value of masterStatus[7:0]
        // stat.stat1 returns the value of masterStatus[15:8]

        // stat.stat2 returns the value of masterStatus[23:16]

        // stat.stat3 returns the value of masterStatus[31:24]
        // but in synthesis, it gives [Synth 8-524] part-select[7:0]  out of range of prefix stat1 error
        assign stat0Out = stat.stat0[7:0];
        assign stat1Out = stat.stat1[7:0];
        assign stat2Out = stat.stat2[7:0];
        assign stat3Out = stat.stat3[7:0];
        // This assignment gives no synthesis error,
        // but in simulation, 

        // stat.stat0 returns the value of masterStatus[7:0]
        // stat.stat1 returns 0

        // stat.stat2 returns 0

        // stat.stat3 returns 0

        assign stat0Out = stat.stat0[7:0];
        assign stat1Out = stat.stat1[15:8];
        assign stat2Out = stat.stat2[23:16];
        assign stat3Out = stat.stat3[31:24];

endmodule // test1


The comments tell the story. In synthesis,  stat0 must be specified with the range [7:0], stat1 with the range [15:8], stat2 with the range [23:16] and stat3 with the range [31:24] 


In simulation stat0, stat1, stat2 and stat3 all must be specified with the range [7:0]



Here's a testbench to try it out:

module testbench();
    logic [31:0]StatusIn;
    logic [7:0]stat0Out;
    logic [7:0]stat1Out;
    logic [7:0]stat2Out;
    logic [7:0]stat3Out;

    assign StatusIn = 32'h12345678;

    top t (.*);

endmodule // testbench


I'd like everything to work the way that the simulation works. Am I asking interfaces to do something that they weren't intended to do, is this a Vivado bug or is there another way to make interfaces work to hide data ranges?



Joe Samson

Tags (2)
4 Replies
Registered: ‎09-16-2009



My first reaction was thinking that Vivado did NOT support modport expressions.  But 'lo and behold UG901 lists modport expressions as explicitly SUPPORTED.  I've found UG901 to me quite out-of-date and things listed as not supported (or not even called out at all), are in fact, supported.


However, your case is the opposite - listed by Xilinx as supported, but not generating the correct logic.


I've used SystemVerilog a lot in Vivado, but not used modport expressions.  Your use case appears valid to me, and it looks like a Vivado bug.  I think your testcase should be looked at by Xilinx developers.  Kudos for creating the small testcase which shows the issue.




0 Kudos
Registered: ‎10-05-2010

Thanks, Mark. I have actually found other modport bugs, but this is the simplest one to demonstrate. I have no idea which behavior is actually correct.


MODS - Is anyone going to look at this problem?




Joe Samson

0 Kudos
Registered: ‎10-05-2010

Still failing in Vivado 2017.4





0 Kudos
Registered: ‎03-29-2018

It gets worse, if your interface goes down two levels of heirarchy, the second level will all show up as undriven so the synthesizer grounds all of the signals.


You may not notice this (we didn't) until I tried to add an ILA to the signals. At that time, flip-flop outputs and GND were connected, generating CRC errors! Vivado literally created invalid logic.