Как правильно умножить std_logi c: vector в VHDL? - PullRequest
0 голосов
/ 29 февраля 2020

Итак, я пытаюсь создать модуль для управления серводвигателем 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», выход будет «0 ccc», переводя серводвигатель в исходное положение. «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, но это просто дает мне больше ошибки. Единственное другое решение, о котором я могу подумать, - это делать одно за другим, используя гигантскую структуру case.

, если я использую «unsigned», я получаю ошибку нескольких определений unsigned.

1 Ответ

0 голосов
/ 01 марта 2020

Математика этого проста:

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 выбирает масштабированные значения из справочной таблицы, предварительно рассчитанной компилятором.

Масштаб

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;

Test Bench

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

Simulation of Scale.V2

RTL Scale.V2

RTL of Scale.V2

Пост-отображение Scale.V2

Post mapping of Scale

Сравнение синтеза для FPGA

Архитектура V1

  • 25 logi c элементы с арифметикой с фиксированной точкой c.
  • Нет таблицы поиска.
  • STEP_SIZE имеет тип натуральный.
    • V1a: Целое число.
    • V1b: Номер с фиксированной точкой.
  • Переменные ошибки округления в зависимости от количества запасных битов для арифметики с фиксированной точкой c, например, 19 запасных битов со значениями OP.

Архитектура V2

  • 16 логических c элементов. Quartus несколько оптимизировал дизайн после нескольких компиляций. Изначально использовалось 54 элемента logi c.
  • Используется справочная таблица.
  • STEP_SIZE имеет тип real.
  • Меньшие ошибки округления.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...