如何在 vhdl 中将大整数转换为小整数?

How to convert big integers to smaller integers in vhdl?

我有 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)。

马修

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

正如@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
# us : 5

使用括号解决问题:

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

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

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;

对了,这个操作叫做裁剪

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

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;