Home Articles

如何生成具有不同连接的接口数组?

Asked
Viewed 1828 times
1

我已经声明了以下界面:

interface data_x #(parameter g_DataWidth = 8)
   (input ckrs_t ClkRs_ix);
   logic [g_DataWidth-1:0] data;
   bit         enable;
   ckrs_t ClkRs;

   always_comb begin
      ClkRs = ClkRs_ix;
   end
endinterface

接口具有数据总线和数据使能,并且它还与时钟和复位信号相关联,这是一个typedef ckrs_t .

我有一个模块,它接受这些接口的参数数组:

module fourmclinks
   (...
    data_x packet_ox[NUMBER_OF_GBT_LINKS-1:0],
    data_x packet_ix[NUMBER_OF_GBT_LINKS-1:0],
    ...
    );

我遇到的问题是,我需要在顶级实体中声明这些data_x接口的数组,但每次使用不同的ClkRs_ix输入时钟 . (它用于gbts,其中每个接收器都有自己的时钟和复位信号) .

我尝试了很多东西,包括这个:

ckrs_t txclock_x;
   assign txclock_x.clk = GbtTxFrameClk40MHz_k;
   assign txclock_x.reset = GbtReset_r;
   data_x #(.g_DataWidth(g_FrameSize)) packet_ox[NUMBER_OF_GBT_LINKS-1:0](.ClkRs_ix(txclock_x));

   data_x #(.g_DataWidth(g_FrameSize)) packet_ix[NUMBER_OF_GBT_LINKS-1:0]();
   genvar                 linkiface;
   generate
      for(linkiface=1; linkiface < NUMBER_OF_GBT_LINKS+1; linkiface++) begin : linkgenerator
     assign packet_ix[linkiface-1].ClkRs_ix.clk =
                             GbtRxFrameClk40Mhz_kb4[linkiface];
     assign packet_ix[linkiface-1].ClkRs_ix.reset = GbtReset_r;
     assign packet_ix[linkiface-1].enable = 0;
     assign packet_ix[linkiface-1].data = RxDataAppSfpGbtUserData_4b80[linkiface];
      end
   endgenerate

因此,进行空/虚/未分配/ ...接口数组声明,然后在生成循环中为其分配正确的信号 . 这模拟,但quartus没有编译它声称

值不能分配给输入“ClkRs_ix” .

如何正确生成接口数组,每个接口都有不同的输入连接?请帮忙

1 Answer

  • 0

    我现在有点聪明,所以这里是问题的解决方案 . 但首先是问题:

    • 不可能只是从上面的data_x接口声明中的端口声明中删除'input'方向 . 如果这样做,则必须为data_x对象的每个实例手动分配时钟和重置行 . 这确实是可能的,但是在实例化界面期间,人们失去了时钟和重置自动分配的所有美妙之处

    • 在这种特殊情况下,不可能 Build 虚拟接口,并在for循环中连接信号 . 造成这种情况的根本原因是always_comb的存在,它接收输入复位/时钟并将其分配给内部信号 . 因此,此分配以及顶级实体中的复位和时钟的手动分配导致从两个源驱动这些信号,Quartus将不会消化这些信号

    所以唯一可行的方法,我发现如下:

    声明data_x接口以按需生成always_comb:

    interface data_x #(
              parameter g_hasClock = 1,
              parameter g_DataWidth = 8)
       (
        input ckrs_t ClkRs_ix
        );
    
       logic [g_DataWidth-1:0] data;
       bit         enable;
       ckrs_t ClkRs;
    
       generate
          if(g_hasClock) begin
         always_comb begin
            ClkRs = ClkRs_ix;
         end
          end
       endgenerate
    
    endinterface // data_x
    

    使用未绑定的ClkRs_ix实例化接口 . 注意g_hasClock的用法,它实例化没有always_comb块的data_x接口,因此Quartus停止抱怨多个驱动程序:

    data_x #(.g_DataWidth(g_FrameSize),
            .g_hasClock(0)) packet_ix[NUMBER_OF_GBT_LINKS-1:0]();
    

    然后生成不同时钟的接口:

    genvar                 linkiface;
       generate
          for(linkiface=1; linkiface < NUMBER_OF_GBT_LINKS+1; linkiface++)
       begin : linkgenerator
    
         assign packet_ix[linkiface-1].ClkRs.clk = GbtRxFrameClk40Mhz_kb4[linkiface];
         assign packet_ix[linkiface-1].ClkRs.reset = GbtReset_r;
         assign packet_ix[linkiface-1].enable = 0;
         assign packet_ix[linkiface-1].data = RxDataAppSfpGbtUserData_4b80[linkiface];
          end
       endgenerate
    

    这有效 . 它不是那么好,因为我们必须手动完成它 . 仅仅为了完整性:如果所有接口的时钟都相同,那么上面的所有代码都归结为这个代码片段:

    ckrs_t txclock_x, rxclock_x;
       assign txclock_x.clk = GbtTxFrameClk40MHz_k;
       assign txclock_x.reset = GbtReset_r;
       data_x #(.g_DataWidth(g_FrameSize)) packet_ox[NUMBER_OF_GBT_LINKS-1:0](.ClkRs_ix(txclock_x));
    

    我确信这不是有史以来最好的解决方案,但它是可编译的,并提供所需的结果 .

Related