【问题标题】:VHDL, using functions in for generate statementVHDL,使用 for generate 语句中的函数
【发布时间】:2013-09-22 07:17:51
【问题描述】:

VHDL,使用 for generate 语句中的函数

我有一个组件应该被实例化大约 8000 次,我在一些常量值的帮助下使用了 for-generate 语句来减少代码量,但是我必须声明一个函数来对组件连接进行参数化。

我的函数如下所示:

    function dim1_calc (
      cmp_index : integer;
      prt_index : integer
      ) return integer is
      variable updw   : integer := 0;
      variable shft_v : integer := 0;
      variable result : integer := 0;
    begin

      if (cmp_index < max_up) then
        updw := 1;
      else
        updw := 2;
      end if;

      case prt_index is
        when 1 =>
          shft_v := cnst_rom(updw)(1) + (i-1);
        when 2 =>
          shft_v := cnst_rom(updw)(2) + (i);
          --
          --
          --
        when 32 =>
          shft_v := cnst_rom(updw)(32) + (i);
        when others =>
          shft_v := 0;
      end case;

      if (updw = 1) then
        if (shft_v = min_up & ((prt_index mod 2) = 0)) then
          result <= max_up;
        elsif (shft_v = max_up & ((prt_index mod 2) = 1)) then
          result <= min_up;
        elsif (shft_v < max_up) then
          result <= shft_v;
        else
          result <= shft_v - max_up;
        end if;
      else
        --something like first condition statements...
        --
        --
      end if;


      return result;

    end function;

我使用此函数的部分代码加上一些相关部分如下所示:

    --these type definitions are in my package
      type     nx_bits_at is array (natural range <>) of std_logic_vector (bits-1 downto 0);
      type     mxn_bits_at is array (natural range <>) of nx_bits_at;
    --
    --
    --
      component pn_cmpn is
        port(
          clk      : in  std_logic;
          bn_to_pn : in  nx_bits_at(1 to row_wght);
          pn_to_bn : out nx_bits_at(1 to row_wght)
          );
      end component;
      --
      --
      --
      signal v2c : mxn_bits_at(1 to bn_num)(1 to col_wght);
      signal c2v : mxn_bits_at(1 to pn_num)(1 to row_wght);
      --
      --
      --
      gen_pn : for i in (1 to pn_num) generate

        ins_pn : pn_cmpn port map (
        clk          => clk,
        bn_to_pn(1)  => b2p (dim1_calc(i, 1)) (dim2_calc(i, 1)),
        bn_to_pn(2)  => b2p (dim1_calc(i, 2)) (dim2_calc(i, 2)),
        .
        .
        .
        bn_to_pn(32) => b2p (dim1_calc(i, 32)) (dim2_calc(i, 32)),
        pn_to_bn     => p2b (i)
        );

      end generate;

我知道一起使用太多的顺序语句通常是不合适的,我尽可能避免使用它们,但是在这种情况下,我假设这个函数不会合成到一些真实的硬件中,而合成器只是计算输出值并将其放入该组件的相应实例中。我对吗?或者与仅 8000 个实例相比,这种编码方式会导致额外的硬件。

PS1:最初我使用“0 到...”来定义数组的第 2 维和第 3 维的范围,但由于基于 for-generate 语句参数的维计算函数产生了混淆,我将它们替换了用“1 到...”。这样好吗!编码风格还是应该避免?

PS2:有没有办法将上面代码中的端口映射部分组合成这样的东西: (我知道这是大错特错,只是澄清我想要的)

      gen_pn : for i in (1 to pn_num) generate

        ins_pn : pn_cmpn port map (
        clk          => clk,

        gen_bn_to_pn : for j in (1 to 32) generate
            bn_to_pn(j)  => b2p (dim1_calc(i, j)) (dim2_calc(i, j)),
        end generate;

        pn_to_bn     => p2b (i)
        );

      end generate;

让我再举一个例子 假设我有一个这样的组件实例化:

    ins_test : test_comp port map (
        clk          => clk,
        test_port(1)  => test_sig(2)
        test_port(2)  => test_sig(3)
        test_port(3)  => test_sig(4)
        );

有什么方法可以在这里生成吗?类似:

    ins_test : test_comp port map (
        clk          => clk,
        gen_pn : for i in (1 to 3) generate
            test_port(i)  => test_sig(i+1)
        end generate;
        );

PS3:是否可以在 VHDL 中调用另一个函数中的函数?

【问题讨论】:

    标签: function vhdl


    【解决方案1】:

    函数可以通过这种方式使用。如果您遇到问题,我相信他们会在设计或设计工具中考虑细节,而不是基本方法。

    一个潜在的问题是函数引用了一些外部“事物”,例如max_up, i, cnst_rom,其声明既不是函数的一部分,也不是函数的参数。这使它成为一个“不纯函数”——因为它引用外部状态甚至修改它——对调用它有限制(因为外部状态可能会改变,结果可能取决于评估顺序等)。

    如果你能让它变得纯净,那就去做吧。我有一种感觉 max_up, cnst_rom 是常量:如果它们没有在其他地方使用,请将它们声明为函数的本地。而i 可能应该是一个参数。

    如果无法做到这一点,请将外部声明设为常量,并最好将它们和函数一起包装在一个包中。

    这只会以小的、可理解的、可维护的形式生成您需要的值,而不是无限量的硬件。我使用了一组复杂的函数嵌套来执行浮点运算,然后进行繁琐的范围缩减和整数舍入来初始化查找表,所以基本上这种方法确实有效。

    潜在的陷阱:

    有些设计工具在使用完全有效的 VHDL 时会遇到问题,如果它的使用有点不正统的话。 Synplicity 不能合成某些形式的函数(它们会生成硬件),尽管通过 OUT 参数返回结果的等效过程没有问题! XST 要好得多。

    XST 解析我的查找表 init 有一个荒谬的减速,函数调用的数量呈二次方。但前提是您使用的是旧的 VHDL 解析器(Spartan-3 的默认值)。 Spartan-6 使用新的解析器并且工作正常(不到一秒而不是半小时!),Modelsim 和 Isim 也是如此。 (还没有在那个项目上尝试过 Synplicity)

    一些工具反对端口映射中的非正统事物:您可能会在那儿进行函数调用;或者您可能必须通过调用初始化常量并在端口映射中使用这些常量来解决工具错误。

    还有你的补充问题:

    PS1) 数组范围的正确编码风格是......无论什么让你的意图清晰。 如果您发现自己在精神上偏移了 1 并且感到困惑甚至犯错误,请停止!并改进设计。

    一些不错的数组索引样式:

    type colour is (red, green, blue);
    subtype brightness is natural range 0 to 255;
    
    hue : array (colour) of brightness;
    gamma : array (brightness) of brightness;
    -- here 0 is a legitimate value
    channel : array (1 to 99) of frequency; 
    

    PS2)我想你是在问你是否可以嵌套生成语句。是的。

    细节可能很尴尬和困难,但是是的。

    PS3) 当然可以!你甚至可以声明其他人本地的函数;消除了他们会在没有意义的地方被意外调用的可能性。它们(不纯函数)可以访问外部函数(或进程)的执行范围,从而简化参数列表。

    【讨论】:

    • 感谢您的回答。你对 max_up、cnst_rom 和 i 的感觉是对的,我会让我的函数变得纯粹。我的合成器是XST,我的FPGA是virtex-5,这样就可以了。关于数组索引样式:谢谢,那是一种解脱 :) 是的,我问的是嵌套生成语句。但这是一个特例,显然我没有很好地解释它。我添加了另一个示例以进行说明。
    【解决方案2】:
    Q1 - in this case I assumed that this function won't synthesize into some ...  
    

    这取决于您使用的合成器。请参阅下面的this 相关问题和 cmets。


    Q2 - PS1: Initially I used "0 to..." for defining ranges of the ...  
    

    当然没问题。请允许我们在这里发布关于编码风格的建议。 (来自this book
    在定义循环参数规范时,要么使用类型(或子类型)定义,要么使用预定义的对象属性(例如,PredefinedObject'range、PredefinedObject'length - 1 downto 0)。避免使用离散范围(例如,1 到 4)。
    此规则使代码更易于重用和灵活维护。


    Q3 - PS2: Is there a way that port mapping part in above code combines into ...  
    

    我想这就是你问第四个问题的原因。所以参考下一个答案:)。


    Q4 - Is it possible to call a function inside another function in VHDL?  
    

    虽然我找不到对此的官方参考,但答案是肯定的。

    PS:编码规则由合成器工具定义。所以找到答案的最好方法就是自己尝试一下。

    【讨论】:

    • 当然感谢您的回答和参考。我的合成器是 XST,幸好不会有问题。我不知道我的最后两个问题是有联系的!所以请让我知道如何将函数用于我的目的。关于你的 PS:我会牢记这一点,并且会更频繁地这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多