如何使用 2 补码在 VHDL 中将向量除以二?
How to divide a vector by two in VHDL using 2 complement?
我有一个向量,我想将它除以 2 in 2 complement。我做了以下操作,但我完全不确定这是否好。是否正确,有什么帮助吗?
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 :((((((((((((((((((((
提前致谢!
Any help if this is correct or not?
这是不正确的。原因是由于在模拟过程中会出现语义错误(此处未显示,该问题缺少 Minimal, Complete and Verifiable example)。
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 Synthesis)支持 VHDL 除以 2 的幂的静态右操作数,如此处所示。请参阅用户指南中的 Table 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 shifting without adjustment 的报告显示结果是错误的。
第二个 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 工具中预定义的。包含在此处以支持较旧的模拟器。
我有一个向量,我想将它除以 2 in 2 complement。我做了以下操作,但我完全不确定这是否好。是否正确,有什么帮助吗?
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 :((((((((((((((((((((
提前致谢!
Any help if this is correct or not?
这是不正确的。原因是由于在模拟过程中会出现语义错误(此处未显示,该问题缺少 Minimal, Complete and Verifiable example)。
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 Synthesis)支持 VHDL 除以 2 的幂的静态右操作数,如此处所示。请参阅用户指南中的 Table 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 shifting without adjustment 的报告显示结果是错误的。
第二个 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 工具中预定义的。包含在此处以支持较旧的模拟器。