0

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 to...”来定义我的数组的第 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 中调用另一个函数中的函数?

4

2 回答 2

2

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

一个潜在的问题是函数引用了一些外部“事物”,例如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)当然是的!你甚至可以声明其他人本地的函数;消除了他们会在没有意义的地方被意外调用的可能性。它们(不纯函数)可以访问外部函数(或进程)的执行范围,从而简化参数列表。

于 2013-09-22T08:26:05.227 回答
0
Q1 - in this case I assumed that this function won't synthesize into some ...  

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


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

肯定没问题。请允许我们在这里发布关于编码风格的建议。(摘自本书
在定义循环参数规范时,要么使用类型(或子类型)定义,要么使用预定义的对象属性(例如,PredefinedObject'range、PredefinedObject'length - 1 down to 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:编码规则由合成器工具定义。因此,找到答案的最佳方法是自己尝试。

于 2013-09-22T08:34:11.567 回答