vhdl中的算术运算。如何将std_逻辑向量乘以实数?
对于学校教程,我需要制作一个组件,该组件接收0到1000之间的整数值。输出返回S=V*C,其中C取决于: 当V在[0,10]范围内时,C=1 当V在[11100]范围内时,C=0.75 当V在[1011000]范围内时,C=0.3125 我尝试了下面的代码,但无法编译。我想,我对类型有问题。如何编程实数与标准逻辑向量相乘 将V信号添加到过程灵敏度列表中; 用移位和加法代替布赖恩说的直接乘法。vhdl中的算术运算。如何将std_逻辑向量乘以实数?,vhdl,Vhdl,对于学校教程,我需要制作一个组件,该组件接收0到1000之间的整数值。输出返回S=V*C,其中C取决于: 当V在[0,10]范围内时,C=1 当V在[11100]范围内时,C=0.75 当V在[1011000]范围内时,C=0.3125 我尝试了下面的代码,但无法编译。我想,我对类型有问题。如何编程实数与标准逻辑向量相乘 将V信号添加到过程灵敏度列表中; 用移位和加法代替布赖恩说的直接乘法。 您的问题并不完全清楚:您需要代码做什么。根据您的答案,实际上有多种解决方案 优先问题:表示和舍入 正如您
您的问题并不完全清楚:您需要代码做什么。根据您的答案,实际上有多种解决方案 优先问题:表示和舍入 正如您已经发现的,看到您使用的是数值型的,std逻辑向量本身并不表示任何值。它只是一个std_逻辑元素的数组。因此,您不应该对裸std_逻辑_向量进行任何操作。 现在,通过将向量强制转换为无符号类型,可以将其定义为表示无符号整数值。但是现在你遇到了一个问题,整数不能代表分数。那么整数中的0.1是多少?0那很容易。但整数的0.9是多少?那要看你的取整方案了。如果简单地截断数字,那么答案又是0。但使用标准四舍五入+0.5,答案是1。你还没告诉我们你想要什么舍入方案我不知道你有没有想过 还有,为什么你的s是14位宽?如果V是10位,最大因子是1.0,那么S也只需要10位 启动位置 让我们首先定义一个实体
library ieee;
use ieee.std_logic_1164.all;
entity comp1 is
port(
V : in std_logic_vector(9 downto 0);
S : out std_logic_vector(9 downto 0)
);
end entity;
实际操作
您可以将所有内容转换为浮点实数并执行您的操作。这将为您解决所有舍入问题,您将获得更多自由。问题是合成中还不支持实类型。尽管如此,对于测试来说,它仍然可以正常工作
architecture behavior of comp1 is
signal V_real, S_real : real;
use ieee.numeric_std.all;
begin
V_real <= real(to_integer(unsigned(V)));
S_real <=
V_real when V_real <= 10.0 else
V_real * 0.75 when V_real <= 100.0
else V_real * 0.3125;
S <= std_logic_vector(to_unsigned(integer(S_real), S'length));
end architecture;
定点
在VHDL-2008中,他们试图通过引入可合成的定点软件包来解决合成中没有点表示的问题。使用这些包时,您甚至可以选择所需的舍入方案。这是因为舍入需要额外的资源,并不总是必要的。警告:使用软件包需要一些时间才能习惯
architecture behavior of comp1 is
use ieee.fixed_pkg.all;
signal V_fix : ufixed(9 downto 0);
signal C : ufixed(0 downto -15);
signal S_fix : ufixed(10 downto -15); -- range of V*C+1
use ieee.numeric_std.all;
begin
V_fix <= to_ufixed(V, V_fix);
C <= to_ufixed(1, C) when V_fix <= 10 else
to_ufixed(0.75, C) when V_fix <= 100 else
to_ufixed(0.3125, C);
S_fix <= V_fix * C;
S <= std_logic_vector(to_unsigned(S_fix, S'length));
end architecture;
p、 如前所述,您需要在VHDL-2008模式下编译才能工作
整数运算
如果你看乘法因子,你会发现它们可以用分数表示:
0.75 = 3/4
0.3125 = 5/16
这意味着您可以简单地使用整数算术来执行缩放
architecture behavior of comp1 is
signal V_int, S_int : integer range 0 to 1000;
use ieee.numeric_std.all;
begin
V_int <= to_integer(unsigned(V));
S_int <=
V_int when V_int <= 10 else
V_int*3/4 when V_int <= 100
else V_int*5/16;
S <= std_logic_vector(to_unsigned(S_int, S'length));
end architecture;
NB整数算术没有舍入方案,因此数字被截断
低级优化:Shift和add
在评论中,Brian提到使用shift和add操作。回到我答案的整数算术部分,你会看到分母实际上是2的幂,这可以通过位移位操作来实现
x/4=x/2^2=x>>2右移2
x/16=x/2^4=x>>4右移4
同时,还可以使用位移位和加法操作来实现分子
x*3=x*11b=>x+x我需要从表中选择C,所以我不能只写V_int*3/4。这是我的问题,我无法避免调用C变量或smth并在过程中赋值,而且,在when/if/case部分之后,我必须将V和C相乘。它不起作用不是一个具体的问题描述。请编辑您的问题,以准确显示您看到的问题。请使用slv的无符号intsead,并给出这些常量,我建议使用shift+add而不是乘法。这应该是对我的回答的评论,而不是对你自己的问题的回答;更好的是,编辑你的问题,添加所有重要的细节。什么是smth?关于你的评论:你告诉我们你不能做什么。但是什么是允许的呢?在自然数空间中不可能表示0.75。所以你的老师可能想让你用某种方法来解决这个问题。帮助我们,帮助你。
architecture behavior of comp1 is
signal V_int, S_int : integer range 0 to 1000;
use ieee.numeric_std.all;
begin
V_int <= to_integer(unsigned(V));
S_int <=
V_int when V_int <= 10 else
V_int*3/4 when V_int <= 100
else V_int*5/16;
S <= std_logic_vector(to_unsigned(S_int, S'length));
end architecture;
architecture behavior of comp1 is
use ieee.numeric_std.all;
signal V_uns4, S_uns4 : unsigned(13 downto 0); -- add 4 bits for correct adding
begin
V_uns4 <= resize(unsigned(V),V_uns4'length);
S_uns4 <=
shift_left(V_uns4,4) when V_uns4 <= 10 else
shift_left(V_uns4,3) + shift_left(V_uns4,2) when V_uns4 <= 100 -- "11" >> 2
else shift_left(V_uns4,2) + V_uns4; --"101" >> 4
S <= std_logic_vector(resize(shift_right(S_uns4,4),S'length));
end architecture;
entity comp1_tb is end entity;
library ieee;
architecture tb of comp1_tb is
use ieee.std_logic_1164.all;
signal V,S : std_logic_vector(9 downto 0);
use ieee.numeric_std.all;
signal V_int, S_int : integer range 0 to 1000;
begin
DUT: entity work.comp1
port map(
V => V,
S => S);
V <= std_logic_vector(to_unsigned(V_int, V'length));
S_int <= to_integer(unsigned(S));
V_stim : process begin
V_int <= 1;
wait for 1 ns;
assert (S_int = 1) report "S should be 1*1 = 1;" severity warning;
V_int <= 10;
wait for 1 ns;
assert (S_int = 10) report "S should be 10*1 = 10;" severity warning;
V_int <= 100;
wait for 1 ns;
assert (S_int = 75) report "S should be 100*0.75 = 75;" severity warning;
V_int <= 1000;
wait for 1 ns;
assert (S_int = 312 OR S_int = 313) report "S should be 1000*0.3125 = 312 or 313;" severity warning;
wait;
end process;
end architecture;