首页 > 解决方案 > 如何使用 2 个补码在 VHDL 中将向量除以 2?

问题描述

我有一个向量,我想将它除以 2 补码。我做了以下事情,但我完全不确定这是否好。如果这是否正确,有什么帮助吗?

Data_in  :in  std_logic_vector(15 downto 0) ;

Data_out :out  std_logic_vector(15 downto 0) ;

-- these vectors in 16 it

variable tmp : integer ;

tmp := conv_integer(Data_in  ) / 2 ;

Data_out <= conv_std_logic_vector (tmp,8);
-------- i will add these lines so the question would be posted 
-- come on :((((((((((((((((((((

提前致谢 !

标签: vhdl

解决方案


如果这是否正确,有什么帮助吗?

这是不正确的。原因是在模拟过程中会出现语义错误(此处未显示,该问题缺少最小、完整和可验证的示例)。

Data_out <= conv_std_logic_vector (tmp,8);

右侧表达式的长度由 conv_std_logic_vector 的第二个参数(8)决定。模拟时有一个要求,即目标信号的每个元素的有效值中都有一个元素。(IEEE 标准 1076-2008 14.7.3.4 信号更新,第 2 段,b))。你会得到一个模拟错误。

在您的代码段中更正这一点将传递正确的长度:

Data_out <= conv_std_logic_vector (tmp, 16);

如果没有最小、完整和可验证的示例,就无法确定您是否犯了另一个错误。

类型 INTEGER 具有最小范围(实际范围取决于实现,请参阅 5.2.3.2 预定义整数类型,其中最小范围为 –2147483647 到 +2147483647。没有 VHDL 综合工具支持更宽范围的整数值。对于落在该范围内的二进制值,有使用转换为整数并除以 2 没有错。

从历史上看,您可以使用移位来表示两个除法的幂。

Juergen 的评论建议向右移动一位并保留符号如下所示:

Data_out <= Data_in(15) & Data_in(15 downto 1);

这适用于数字 0 或更大。对于小于数字的数字,由于二进制补码表示,它会向下舍入奇数。这可以通过调整移位输入来克服,将 1 添加到奇数负股息值:

    if Data_in(15) = '1' and Data_in(0) = '1' then -- odd negative numbers 
        Data_out <= SHIFT_RIGHT (Data_in + 1, 1);
    else 
        Data_out <= Data_in(15) & Data_in(15 downto 1); -- SHIFT_RIGHT(Data_In, 1)
    end if;

(Data_in 和 Data_out 以及来自 IEEE 包 numeric_std 的函数 SHIFT_RIGHT 是类型签名的。)

VHDL 综合工具通常可以除以 2 的幂。例如使用 IEEE 包 numeric_std:

Data_out <= std_logic_vector(signed(Data_in) / 2);

其中 std_logic_vector 值被视为二进制补码值(有符号类型)。合成逻辑在没有实际除法器的情况下实现了这一点。

Xilinx Vivado(请参阅UG901 综合)支持 VHDL 除以静态右操作数的 2 次方,如此处所示。请参阅用户指南中的表 5-10 VHDL 构造和支持状态)。

注意:Synopsys 软件包在 Vivado 用户指南中称为旧版软件包。自从 Synopsys 发布他们的 std_logic_arith、std_logic_unsigned 和 std_logic_signed 包以来,综合工具已经发展到处理除法。IEEE 提供标准数值包,其中包括基于 std_logic_1164 的数组类型的除法运算符。

代码示例:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity signed_div_2 is
end entity;

architecture foo of signed_div_2 is
    signal Data_in:  signed (15 downto 0) := (1 => '0', others => '1');
    signal Data_out: signed (15 downto 0);

    function to_string (inp: signed) return string is
            variable image_str: string (1 to inp'length);
            alias input_str:  signed (1 to inp'length) is inp;
        begin
            for i in input_str'range loop
                image_str(i) := 
                     character'VALUE(std_ulogic'IMAGE(input_str(i)));
            end loop;
            return image_str;
        end function;
begin
    process
    begin
        report LF & HT & "Data_in = " & to_string (Data_in) & 
               " (" & integer'image(to_integer(Data_in)) & ")";
        Data_out <= Data_in(15) & Data_in(15 downto 1);
        wait for 0 ns; -- so Data_out is updated
        report LF & "By right shift (wrong)" & LF & HT &
                "Data_out = " & to_string (Data_out) & 
                " (" & integer'image(to_integer(Data_out)) & ")";
        Data_out <= Data_in / 2;
        wait for 0 ns; -- wait for update
        report LF & "Signed divide by 2" & LF & HT &
                "Data_out = " & to_string (Data_out) & 
                " (" & integer'image(to_integer(Data_out)) & ")";
        if Data_in(15) = '1' and Data_in(0) = '1' then -- odd negative numbers 
            Data_out <= SHIFT_RIGHT (Data_in + 1, 1);
        else 
            Data_out <= Data_in(15) & Data_in(15 downto 1);
        end if;
        wait for 0 ns; -- wait for update
        report LF & "By adjusted right shift" & LF & HT &
                "Data_out = " & to_string (Data_out) & 
                " (" & integer'image(to_integer(Data_out)) & ")";
        wait;  -- once only
    end process;
end architecture;

Data_in 和 Data_out 的类型已更改为有符号以避免大量类型转换。模拟模型给出:

ghdl -r signed_div_2
signed_div_2.vhdl:25:9:@0ms:(report note):
  Data_in = 1111111111111101 (-3)
signed_div_2.vhdl:29:9:@0ms:(report note):
By right shift (wrong)
  Data_out = 1111111111111110 (-2)
signed_div_2.vhdl:34:9:@0ms:(report note):
Signed divide by 2
  Data_out = 1111111111111111 (-1)
signed_div_2.vhdl:43:9:@0ms:(report note):
By adjusted right shift
  Data_out = 1111111111111111 (-1)

第一个不调整移位的Data_out报告显示结果是错误的。

第二个 Data_out 报告使用有符号除以 2 并且是正确的。

第三个 Data_out 报告使用奇数负值的调整来给出正确的结果。该调整在综合中实现了一个进位树,它的所有右操作数位都是静态的,并且进位树在 FPGA 中优化实现。

对于不能使用除法运算符并需要调整移位的遗留包或应用程序,可以将来自 numeric_std 的 SHIFT_RIGHT 函数替换为来自包 std_logic_arith 的 SHR 函数,to_integer 函数将类似地由 CONV_INTEGER 替换,to_signed 函数由 CONV_SIGNED 替换。

to_string 函数在 -2008 兼容的 VHDL 工具中预定义。包括在此处以支持较旧的模拟器。


推荐阅读