【问题标题】:How to convert big integers to smaller integers in vhdl?如何将大整数转换为 vhdl 中的小整数?
【发布时间】:2017-04-09 01:36:49
【问题描述】:

我有 VHDL 代码,我试图将像素值相乘。我有以下实体:

entity xGradient is

port(
    clk : in std_logic;
    x11, x12, x13, x21, x22, x23, x31, x32, x33 : in integer range 0 to 255;
    gradientInX : out integer range 0 to 255
);

end xGradient;

我对这些做了如下操作:

gradientInX <= x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

您可能注意到的问题是,从操作中获得的值超出了我的输出整数的可能值范围。发生这种情况时,我的模拟会崩溃。我不知道我想要做什么的正确词,因此似乎无法弄清楚如何解决这个问题,这让我发疯。我基本上只是想截断或减小输出的大小以确保它适合 gradientInX 输出端口。我尝试使用这样的进程块:

-- declared signals
signal gradientMem: integer;

--beginning of my architecture
begin 

SobelOperator : process(gradientMem)

begin
    gradientMem <= x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

    if (gradientMem > 255) then
        gradientMem <= 255;
    elsif (gradientMem < 0) then
        gradientMem <= 0;
    end if;

end process SobelOperator;

然后将 gradientMem 分配给 gradientInX 但由于某种原因它不起作用。任何帮助将不胜感激。注意:我没有包含所有的 VHDL 代码,因为我认为它会不必要地长。我得到的错误消息是操作的信号结果值超出范围(因为结果值为负并且输出的范围仅为 0 到 255)。

马修

【问题讨论】:

  • 您的问题遗漏了两个重要部分:1)gradientMen 的声明和 2)错误消息。 VHDL 检查分配的范围界限。你想创建一个饱和算法。所以用更大的范围定义gradientMem
  • 我刚刚对其进行了编辑以包含这些内容。我想我的主要问题是敏感度列表不正确。我还想知道 VHDL 是否具有整数特定操作,可以强制结果进入某个范围,但我想不存在这样的功能或操作,所以我只需要自己实现它。无论哪种方式,我的问题似乎都解决了。感谢您的回复,并随时添加任何其他内容。

标签: vhdl


【解决方案1】:

这是您应该使用变量而不是信号的少数情况之一。

SobelOperator : process(x11, x21, x31, x13, x23, x33)
    variable gradientMem : integer;
begin
    gradientMem := x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

    if (gradientMem > 255) then
        gradientMem := 255;
    elsif (gradientMem < 0) then
        gradientMem := 0;
    end if;
    gradientInX <= gradientMem;
end process SobelOperator;

顺便说一下,这个操作叫做clipping

如果要截断,过程应该写成这样:

SobelOperator : process(x11, x21, x31, x13, x23, x33)
    variable gradientMem : integer;
begin
    gradientMem := x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

    gradientInX <= gradientMem mod 256;
end process SobelOperator;

【讨论】:

    【解决方案2】:

    正如@Paebbels 在评论中所建议的那样,gradientMem 的范围很可能不足以处理操作的输出。

    注意事项:在整数运算中,中间范围(大部分)被视为 32b 有符号,并在赋值中检查范围。这为综合工具提供了很多推测,并且可以产生比最佳设计更大的设计。

    为了克服这个问题,ieee.numeric_std.all 用于无符号和有符号类型和操作。这给出了对中间向量长度的绝对控制。这也迫使您了解加法、减法、乘法等通常有助于 RTL 设计的情况。

    但是,需要注意的是,在向量形式中,操作是成对评估的,使用两者中最长的一个作为中间向量长度。

    例如:

      process
        variable i1      : integer range 0 to 15 := 15;
        variable i2      : integer range 0 to 15 := 9;
        variable i3      : integer range 0 to 15 := 11;
        variable i4      : integer range 0 to 31 := 2;
        variable iSum    : integer range 0 to 63;
        variable u1      : unsigned(3 downto 0) := to_unsigned(15,4);
        variable u2      : unsigned(3 downto 0) := to_unsigned(9,4);
        variable u3      : unsigned(3 downto 0) := to_unsigned(11,4);
        variable u4      : unsigned(5 downto 0) := to_unsigned(2,6);
        variable uSum    : unsigned(5 downto 0);
      begin
        iSum := i1 + i2 + i3 + i4;
        uSum := u1 + u2 + u3 + u4;
        write(output, "int: " & to_string(iSum) & lf &
                      "us : " & to_string(to_integer(uSum)) & lf);
        wait;
      end process;
    

    给予:

    # int: 37
    # 我们:5

    使用括号解决问题:

    uSum := (u1 + (u2 + (u3 + u4)));
    

    【讨论】:

      【解决方案3】:

      您的进程SobelOperator : process(gradientMem) 的敏感度列表中有错误。这里必须是影响结果信号的信号,换句话说,这是一个进程敏感的信号列表。所以应该有x11x21x31x13x23x33之类的SobelOperator : process(x11, x21, x31, x13, x23, x33)

      【讨论】:

      • 您好,感谢您的回复!是的,我实际上在写下我的问题时注意到了这一点。我会尝试解决这个问题,看看会发生什么。我仍然想知道数字库中是否有一个函数,例如,它将整数信号从一个范围截断到一个更小的范围。
      • 对于输出的截断,您可以使用 std_logic_vector 类型并从总线中获取您需要的位,然后如果您需要输出为 integer 类型,则将其转换为整数
      • 是的,灵敏度列表是错误的,但这不是他的范围问题的原因......
      • @Paebbles 我无法添加 cmets,因为我没有足够的声誉,所以我将其发布为答案。或者我该怎么办?
      • 写一个答案是可以的,但仅仅改变敏感度列表是不够的。它不能解决越界错误。
      猜你喜欢
      • 1970-01-01
      • 2013-02-01
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      • 1970-01-01
      • 2014-10-05
      • 1970-01-01
      相关资源
      最近更新 更多