对于学校教程,我需要创建一个在0到1000区间内接收整数值的组件。输出返回S
= V
* C
,其中C
取决于:
C
在[0,10] 范围内时,V
= 1
当C
在[11,100] V
= 0.75
当C
在范围[101,1000] V
= 0.3125
我尝试了下面的代码,但它没有编译。我猜,我的类型有问题。如何编制real
号码以与std_logic_vector
相乘?
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity comp1 is
port(
V: in std_logic_vector(9 downto 0);
S:out std_logic_vector(13 dowto 0));
end comp1;
architecture syn of comp1 is
begin
process is
variable c: unsigned(4 downto 0);
variable r: unsigned(13 downto 0);
begin
if unsigned(V) < 11 then
c:=1;
elsif unsigned(V) < 101 then
c:=0.75;
elsif others =>
c:=0.3125;
end if;
r:=unsigned(V)*C;
S<=std_logic_vector(r(13 downto 0));
end process;
end architecture;
答案 0 :(得分:0)
您的问题并不完全清楚:您需要什么代码?根据您的答案,实际上有多种解决方案。
正如您已经发现的,看到您使用numeric_std
,std_logic_vector
本身不代表任何值。它只是一个std_logic
元素的数组。因此,您不应该执行裸std_logic_vector
的任何操作。
现在,通过将向量转换为unsigned
类型,可以将其定义为表示(无符号)整数值。但现在你得到的问题是整数不能代表分数。那么整数是0.1?这很容易。但是整数是0.9?那么,这取决于你的舍入计划。如果您只是截断数字,则答案再次为0。但是使用标准舍入(+0.5),答案是1.你没有告诉我们你想要什么样的舍入方案(我不知道你是否想过它)
P.S。为什么你的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;
您可以将所有内容转换为浮点(real
)并执行操作。这将解决你的所有四舍五入,你有很大的自由。问题是合成中不支持real
类型。不过,对于测试来说,它的工作原理应该是
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.S。如上所述,您需要在VHDL-2008模式下进行编译才能使其正常工作。
如果你看一下乘法因子,你会发现它们可以用分数表示:
这意味着你可以简单地使用整数运算来执行缩放。
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 整数算术没有舍入方案,因此数字被截断!
Brian在评论中提到了使用shift和add操作。回到我的答案的整数算术部分,你会看到分母实际上是2的幂,可以使用位移操作来实现
同时,也可以使用bitshift和add操作来实现分子
两者都可以合并为一个操作。注意,虽然你必须记住,左移会丢掉移出的位。这可能会导致问题,因为正确结果需要值的分数。因此,您需要添加位来计算中间结果。
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;
答案 1 :(得分:0)
我需要从表中选择C,所以我不能只写V_int * 3/4。这是我的问题我无法避免调用C变量或smth并在进程中分配值,而且,在/ if / case部分之后,我必须将V和C相乘。
答案 2 :(得分:-2)