您如何在 VHDL 中适当地乘以 std_logic:vector?
How do you appropriately multiply std_logic:vector in VHDL?
我正在尝试制作一个模块来操纵伺服电机 sg90。
但是我在架构的一部分上遇到了问题;该模块有一个 6 位的条目,它控制我想要伺服电机的位置,但用 16 位矢量控制电机。我这样做的方法是乘以一个 6 位变量(与条目具有相同的值)并将其放在 16 位输出向量上,如下所示:
case position is
when "000000" =>
value:= X"0ccc";
when "111111" =>
value := X"1999";
when others =>
value:=std_logic_vector((control*52)+3276);
end case;
这应该做的是,例如,如果我输入“000000”,输出将是“0ccc”,将伺服电机置于其起始位置。 “111111”将是“1999”或结束位置结束之间的所有其他内容都应由该表达式考虑。但是,我收到以下错误:
Error (10327): VHDL error at ServomotorF.vhd(46): can't determine definition of operator ""*"" -- found 0 possible definitions
如果有帮助,我使用的库是
use ieee.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
我也尝试过使用 numeric_std,但这只会给我带来更多错误。
我能想到的唯一其他解决方案是使用巨大的案例结构一个一个地做。
如果我使用“unsigned”,我会收到多个 unsigned 定义的错误。
它的数学原理很简单:
value_out <= value_in * STEP_SIZE + MIN_VALUE_OUT;
但 VHDL 需要更多的努力,本质上:
constant MIN_VALUE_IN: natural := 0;
constant MAX_VALUE_IN: natural := 16#3F#;
constant MIN_VALUE_OUT: natural := 16#0CCC#;
constant MAX_VALUE_OUT: natural := 16#1999#;
constant STEP_SIZE: natural := natural(floor(real(MAX_VALUE_OUT - MIN_VALUE_OUT) / real(MAX_VALUE_IN - MIN_VALUE_IN))); -- Beware of rounding errors.
signal std_in, std_out: std_logic_vector(5 downto 0);
signal value_in, value_out: natural;
value_in <= to_integer(unsigned(std_in));
value_out <= value_in * STEP_SIZE + MIN_VALUE_OUT;
std_out <= std_logic_vector(to_unsigned(value_out, std_out'length));
以下是 VHDL 中定标器的完整实现。 V1 计算 VHDL 中的缩放值,V2 从查找中选择缩放值 table 由编译器预先计算。
规模
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity Scale is
generic
(
MIN_VALUE_IN: natural := 0;
MAX_VALUE_IN: natural := 16#3F#;
MIN_VALUE_OUT: natural := 16#0CCC#;
MAX_VALUE_OUT: natural := 16#1999#
);
port
(
value_in: in natural range MIN_VALUE_IN to MAX_VALUE_IN;
value_out: out natural range MIN_VALUE_OUT to MAX_VALUE_OUT
);
end entity;
architecture V1 of Scale is
constant RANGE_IN: natural := MAX_VALUE_IN - MIN_VALUE_IN;
constant RANGE_OUT: natural := MAX_VALUE_OUT - MIN_VALUE_OUT;
-- V1a
--constant STEP_SIZE: natural := natural(floor(real(RANGE_OUT) / real(RANGE_IN))); -- Beware of rounding errors.
-- V1b
-- Use the spare bits in the natural range for fixed point arithmetic.
constant NATURAL_BITS: natural := natural(log2(real(natural'high))); -- 31
constant USED_BITS: natural := natural(ceil(log2((real(RANGE_OUT) / real(RANGE_IN) * real(MAX_VALUE_IN)))));
constant SPARE_BITS: natural := NATURAL_BITS - USED_BITS; -- 19
constant MULT: real := 2.0**SPARE_BITS;
constant DIV: natural := natural(MULT);
constant HALF: natural := DIV / 2; -- For rounding off the fixed point number.
constant STEP_SIZE: natural := natural(floor(real(RANGE_OUT) * MULT / real(RANGE_IN))); -- Convert to a fixed point number. Accuracy depends on the number of spare bits. Beware of rounding errors.
begin
-- V1a
--value_out <= (value_in - MIN_VALUE_IN) * STEP_SIZE + MIN_VALUE_OUT;
-- V1b
value_out <= ((value_in - MIN_VALUE_IN) * STEP_SIZE + HALF) / DIV + MIN_VALUE_OUT; -- Convert fixed point to natural.
end architecture;
architecture V2 of Scale is
subtype TScaledValue is natural range MIN_VALUE_OUT to MAX_VALUE_OUT;
type TScaledValues is array(MIN_VALUE_IN to MAX_VALUE_IN) of TScaledValue;
function GetScaledValues return TScaledValues is
variable result: TScaledValues;
constant STEP_SIZE: real := real(MAX_VALUE_OUT - MIN_VALUE_OUT) / real(MAX_VALUE_IN - MIN_VALUE_IN);
begin
for i in TScaledValues'range loop
result(i) := natural(real(i - MIN_VALUE_IN) * STEP_SIZE) + MIN_VALUE_OUT;
end loop;
return result;
end function;
constant SCALED_VALUES: TScaledValues := GetScaledValues;
begin
value_out <= SCALED_VALUES(value_in);
end architecture;
测试台
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Scale_TB is
end entity;
architecture V1 of Scale_TB is
constant SYS_CLOCK_FREQ: real := 100000000.0; -- Hz
constant SYS_CLOCK_PERIOD: time := 1.0 sec / SYS_CLOCK_FREQ;
signal halt_sys_clock: boolean := false;
signal sys_clock: std_logic := '0';
constant MIN_VALUE_IN: natural := 0;
constant MAX_VALUE_IN: natural := 16#3F#;
constant MIN_VALUE_OUT: natural := 16#0CCC#;
constant MAX_VALUE_OUT: natural := 16#1999#;
--constant MAX_VALUE_OUT: natural := 7700; -- To see effect of rounding errors for Scale architecture V1.
signal position: natural range MIN_VALUE_IN to MAX_VALUE_IN;
signal servo_pos: natural range MIN_VALUE_OUT to MAX_VALUE_OUT;
signal servo_pos_slv: std_logic_vector(15 downto 0);
component Scale is
generic
(
MIN_VALUE_IN: natural := 0;
MAX_VALUE_IN: natural := 16#3F#;
MIN_VALUE_OUT: natural := 16#0CCC#;
MAX_VALUE_OUT: natural := 16#1999#
);
port
(
value_in: in natural range 0 to 63;
value_out: out natural range MIN_VALUE_OUT to MAX_VALUE_OUT
);
end component;
begin
SysClockGenerator: process
begin
while not halt_sys_clock loop
sys_clock <= '1';
wait for SYS_CLOCK_PERIOD / 2.0;
sys_clock <= '0';
wait for SYS_CLOCK_PERIOD / 2.0;
end loop;
wait;
end process SysClockGenerator;
StimulusProcess: process
begin
for i in MIN_VALUE_IN to MAX_VALUE_IN loop
position <= i;
wait for SYS_CLOCK_PERIOD;
end loop;
wait for SYS_CLOCK_PERIOD;
halt_sys_clock <= true;
wait;
end process;
DUT: Scale
generic map
(
MIN_VALUE_IN => MIN_VALUE_IN,
MAX_VALUE_IN => MAX_VALUE_IN,
MIN_VALUE_OUT => MIN_VALUE_OUT,
MAX_VALUE_OUT => MAX_VALUE_OUT
)
port map
(
value_in => position,
value_out => servo_pos
);
servo_pos_slv <= std_logic_vector(to_unsigned(servo_pos, servo_pos_slv'length));
end architecture;
模拟Scale.V2
Scale.V2 的 RTL
Post 比例映射.V2
FPGA 综合比较
架构V1
- 25 个具有定点运算的逻辑元素。
- 没有查找 table。
- STEP_SIZE 是自然类型。
- V1a:整数。
- V1b:定点数。
- 可变舍入误差取决于定点运算的备用位数,例如19 个带有 OP 值的备用位。
架构 V2
- 16个逻辑元素。 Quartus 在编译几次后对设计进行了更多优化。原来用了54个逻辑元素。
- 使用查找 table。
- STEP_SIZE 是实数类型。
- 更小的舍入误差。
我正在尝试制作一个模块来操纵伺服电机 sg90。 但是我在架构的一部分上遇到了问题;该模块有一个 6 位的条目,它控制我想要伺服电机的位置,但用 16 位矢量控制电机。我这样做的方法是乘以一个 6 位变量(与条目具有相同的值)并将其放在 16 位输出向量上,如下所示:
case position is
when "000000" =>
value:= X"0ccc";
when "111111" =>
value := X"1999";
when others =>
value:=std_logic_vector((control*52)+3276);
end case;
这应该做的是,例如,如果我输入“000000”,输出将是“0ccc”,将伺服电机置于其起始位置。 “111111”将是“1999”或结束位置结束之间的所有其他内容都应由该表达式考虑。但是,我收到以下错误:
Error (10327): VHDL error at ServomotorF.vhd(46): can't determine definition of operator ""*"" -- found 0 possible definitions
如果有帮助,我使用的库是
use ieee.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
我也尝试过使用 numeric_std,但这只会给我带来更多错误。 我能想到的唯一其他解决方案是使用巨大的案例结构一个一个地做。
如果我使用“unsigned”,我会收到多个 unsigned 定义的错误。
它的数学原理很简单:
value_out <= value_in * STEP_SIZE + MIN_VALUE_OUT;
但 VHDL 需要更多的努力,本质上:
constant MIN_VALUE_IN: natural := 0;
constant MAX_VALUE_IN: natural := 16#3F#;
constant MIN_VALUE_OUT: natural := 16#0CCC#;
constant MAX_VALUE_OUT: natural := 16#1999#;
constant STEP_SIZE: natural := natural(floor(real(MAX_VALUE_OUT - MIN_VALUE_OUT) / real(MAX_VALUE_IN - MIN_VALUE_IN))); -- Beware of rounding errors.
signal std_in, std_out: std_logic_vector(5 downto 0);
signal value_in, value_out: natural;
value_in <= to_integer(unsigned(std_in));
value_out <= value_in * STEP_SIZE + MIN_VALUE_OUT;
std_out <= std_logic_vector(to_unsigned(value_out, std_out'length));
以下是 VHDL 中定标器的完整实现。 V1 计算 VHDL 中的缩放值,V2 从查找中选择缩放值 table 由编译器预先计算。
规模
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity Scale is
generic
(
MIN_VALUE_IN: natural := 0;
MAX_VALUE_IN: natural := 16#3F#;
MIN_VALUE_OUT: natural := 16#0CCC#;
MAX_VALUE_OUT: natural := 16#1999#
);
port
(
value_in: in natural range MIN_VALUE_IN to MAX_VALUE_IN;
value_out: out natural range MIN_VALUE_OUT to MAX_VALUE_OUT
);
end entity;
architecture V1 of Scale is
constant RANGE_IN: natural := MAX_VALUE_IN - MIN_VALUE_IN;
constant RANGE_OUT: natural := MAX_VALUE_OUT - MIN_VALUE_OUT;
-- V1a
--constant STEP_SIZE: natural := natural(floor(real(RANGE_OUT) / real(RANGE_IN))); -- Beware of rounding errors.
-- V1b
-- Use the spare bits in the natural range for fixed point arithmetic.
constant NATURAL_BITS: natural := natural(log2(real(natural'high))); -- 31
constant USED_BITS: natural := natural(ceil(log2((real(RANGE_OUT) / real(RANGE_IN) * real(MAX_VALUE_IN)))));
constant SPARE_BITS: natural := NATURAL_BITS - USED_BITS; -- 19
constant MULT: real := 2.0**SPARE_BITS;
constant DIV: natural := natural(MULT);
constant HALF: natural := DIV / 2; -- For rounding off the fixed point number.
constant STEP_SIZE: natural := natural(floor(real(RANGE_OUT) * MULT / real(RANGE_IN))); -- Convert to a fixed point number. Accuracy depends on the number of spare bits. Beware of rounding errors.
begin
-- V1a
--value_out <= (value_in - MIN_VALUE_IN) * STEP_SIZE + MIN_VALUE_OUT;
-- V1b
value_out <= ((value_in - MIN_VALUE_IN) * STEP_SIZE + HALF) / DIV + MIN_VALUE_OUT; -- Convert fixed point to natural.
end architecture;
architecture V2 of Scale is
subtype TScaledValue is natural range MIN_VALUE_OUT to MAX_VALUE_OUT;
type TScaledValues is array(MIN_VALUE_IN to MAX_VALUE_IN) of TScaledValue;
function GetScaledValues return TScaledValues is
variable result: TScaledValues;
constant STEP_SIZE: real := real(MAX_VALUE_OUT - MIN_VALUE_OUT) / real(MAX_VALUE_IN - MIN_VALUE_IN);
begin
for i in TScaledValues'range loop
result(i) := natural(real(i - MIN_VALUE_IN) * STEP_SIZE) + MIN_VALUE_OUT;
end loop;
return result;
end function;
constant SCALED_VALUES: TScaledValues := GetScaledValues;
begin
value_out <= SCALED_VALUES(value_in);
end architecture;
测试台
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Scale_TB is
end entity;
architecture V1 of Scale_TB is
constant SYS_CLOCK_FREQ: real := 100000000.0; -- Hz
constant SYS_CLOCK_PERIOD: time := 1.0 sec / SYS_CLOCK_FREQ;
signal halt_sys_clock: boolean := false;
signal sys_clock: std_logic := '0';
constant MIN_VALUE_IN: natural := 0;
constant MAX_VALUE_IN: natural := 16#3F#;
constant MIN_VALUE_OUT: natural := 16#0CCC#;
constant MAX_VALUE_OUT: natural := 16#1999#;
--constant MAX_VALUE_OUT: natural := 7700; -- To see effect of rounding errors for Scale architecture V1.
signal position: natural range MIN_VALUE_IN to MAX_VALUE_IN;
signal servo_pos: natural range MIN_VALUE_OUT to MAX_VALUE_OUT;
signal servo_pos_slv: std_logic_vector(15 downto 0);
component Scale is
generic
(
MIN_VALUE_IN: natural := 0;
MAX_VALUE_IN: natural := 16#3F#;
MIN_VALUE_OUT: natural := 16#0CCC#;
MAX_VALUE_OUT: natural := 16#1999#
);
port
(
value_in: in natural range 0 to 63;
value_out: out natural range MIN_VALUE_OUT to MAX_VALUE_OUT
);
end component;
begin
SysClockGenerator: process
begin
while not halt_sys_clock loop
sys_clock <= '1';
wait for SYS_CLOCK_PERIOD / 2.0;
sys_clock <= '0';
wait for SYS_CLOCK_PERIOD / 2.0;
end loop;
wait;
end process SysClockGenerator;
StimulusProcess: process
begin
for i in MIN_VALUE_IN to MAX_VALUE_IN loop
position <= i;
wait for SYS_CLOCK_PERIOD;
end loop;
wait for SYS_CLOCK_PERIOD;
halt_sys_clock <= true;
wait;
end process;
DUT: Scale
generic map
(
MIN_VALUE_IN => MIN_VALUE_IN,
MAX_VALUE_IN => MAX_VALUE_IN,
MIN_VALUE_OUT => MIN_VALUE_OUT,
MAX_VALUE_OUT => MAX_VALUE_OUT
)
port map
(
value_in => position,
value_out => servo_pos
);
servo_pos_slv <= std_logic_vector(to_unsigned(servo_pos, servo_pos_slv'length));
end architecture;
模拟Scale.V2
Scale.V2 的 RTL
Post 比例映射.V2
FPGA 综合比较
架构V1
- 25 个具有定点运算的逻辑元素。
- 没有查找 table。
- STEP_SIZE 是自然类型。
- V1a:整数。
- V1b:定点数。
- 可变舍入误差取决于定点运算的备用位数,例如19 个带有 OP 值的备用位。
架构 V2
- 16个逻辑元素。 Quartus 在编译几次后对设计进行了更多优化。原来用了54个逻辑元素。
- 使用查找 table。
- STEP_SIZE 是实数类型。
- 更小的舍入误差。