VHDL,使用函数生成语句

时间:2013-09-22 07:17:51

标签: function vhdl

VHDL,使用生成语句中的函数

我有一个应该实例化大约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 to ...”来定义我的数组的第二维和第三维的范围,但是由于基于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中调用另一个函数内的函数?

2 个答案:

答案 0 :(得分:2)

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

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

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

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

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

潜在的陷阱:

如果一些设计工具的使用稍微不正统,那么它们就会遇到完全有效的VHDL问题。 Synplicity无法合成某些形式的函数(DO生成硬件),虽然通过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)当然可以!您甚至可以向其他人声明本地功能;消除了他们无意中被称为某个地方的可能性。它们(不纯函数)可以访问外部函数(或进程)的执行范围,从而简化参数列表。

答案 1 :(得分:0)

Q1 - in this case I assumed that this function won't synthesize into some ...  

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


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:编码规则由合成器工具定义。因此,找到答案的最佳方法是亲自尝试。