Как я могу указать сигналы «пофиг» в VHDL?

11

На курсах «Логическое проектирование» мы все узнали, что можно минимизировать логическую функцию, например, используя карту Карно или алгоритм Куайна – МакКласки . Мы также узнали, что значения «Не волнует» увеличивают потенциал минимизации.

Например возьмите файл реестра. write_addressИ write_dataсигналы на самом деле не имеет значения , когда write_enableсигнал '0'. Таким образом, им должно быть присвоено значение «Не заботиться», чтобы позволить больше оптимизаций в логике, управляющей этими сигналами (т.е. не в самом файле регистра).

Как правильно указать такие значения «Не волнует» в VHDL, чтобы предоставить инструменту синтеза больше места для возможных оптимизаций?


До сих пор я нашел следующие вещи, которые могут быть подходящими. Но я не совсем уверен, каковы плюсы и минусы каждого подхода:

  • Просто не присваивать сигнал. Кажется, это может сработать. Однако я обнаружил, что это не работает, когда вы хотите определить константу «ничего не делать» некоторого recordтипа, поскольку константы записи должны быть полностью определены (по крайней мере, Modelsim говорит мне об этом).
  • std_logic_1164Пакет определяет значение '-' -- Don't careдля std_ulogic. Похоже, что это семантически правильный выбор для явного «пофиг», но я никогда не видел, чтобы он использовался где-либо (кроме несвязанных конструкций VHDL-2008 case?).
  • Modelsim использует это значение 'X'для отображения неопределенных сигналов. Однако я не уверен, что инструменты синтеза понимают явное 'X'назначение как «все равно».

Вот упрощенный фрагмент кода для пояснения, где я инициализировал сигналы пофиг '-'.

Как вы можете видеть, сигнал control.reg_write_addressможет иметь 3 различных значения: "----", instruction(11 downto 8);и instruction(3 downto 0);. Теперь я ожидаю, что это будет синтезировано в мультиплексор с 2 входами, если '-'интерпретируется как «все равно». Если бы я инициализировал сигнал (others => '0')вместо '-', инструмент должен был бы генерировать 3-х входной мультиплексор.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package mytypes is
    type control_signals_t is record
        write_enable  : std_logic;
        write_address : std_ulogic_vector(3 downto 0);
        read_address  : std_ulogic_vector(3 downto 0);
    end record;

    -- All members of this constant must be fully specified.
    -- So it's not possible to simply not assign a value.
    constant CONTROL_NOP : control_signals_t := (
        write_enable  => '0',
        write_address => (others => '-'),
        read_address  => (others => '-')
    );
end package;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library cfx;
use cfx.mytypes.all;

entity control_unit is
    port(
        instruction : in  std_ulogic_vector(15 downto 0);
        write_data  : out std_ulogic_vector(15 downto 0);
        ctrl        : out control_signals_t
    );
end entity;

architecture rtl of control_unit is
begin
    decode_instruction : process(instruction) is
    begin
        -- Set sensible default values that do nothing.
        -- Especially all "write_enable" signals should be '0'.
        -- Everything else is mostly irrelevant (don't care).
        ctrl       <= CONTROL_NOP;
        write_data <= (others => '-');

        if instruction(15 downto 12) = "1100" then
            -- Load 8 bit of data into the register file
            ctrl.write_enable  <= '1';
            write_data         <= std_ulogic_vector(resize(signed(instruction(7 downto 0)), 16));
            ctrl.write_address <= instruction(11 downto 8);
        elsif instruction(15 downto 8) = "11111001" then
            -- Load 4 bit of data into the register file
            write_data         <= std_ulogic_vector(resize(signed(instruction(7 downto 4)), 16));
            ctrl.write_address <= instruction(3 downto 0);
        elsif instruction(15 downto 8) = "10110101" then
            -- Read from the register file. Don't use the write signals at all.
            ctrl.read_address <= instruction(3 downto 0);
        end if;
    end process;
end architecture;
ломаться
источник
Не могли бы вы рассказать, что вы пытаетесь сделать write_addressи с чем write_data? Какую оптимизацию вы ожидаете провести?
fru1tbat
Я надеюсь, что пример проясняет, чего я хочу достичь.
Фриц

Ответы:

9

Я оставлю это на усмотрение эксперта по LRM, чтобы дать более подробный ответ, но вкратце, ваш подход должен быть верным - я провел быстрый тест с последней версией Quartus, и он обрабатывает, '-'как и положено - сгенерированная логика сокращена как и следовало ожидать, когда выход по умолчанию '-'( 'X'тоже работает, кстати). Подробнее о подходах, которые вы перечислили:

  • Конечно, если вы не хотите использовать защелки, не назначайте сигнал для вашего примера. Если это синхронизированный процесс, вам будет немного лучше, но вы все равно получите разрешения там, где они могут вам не понадобиться. Может быть, я скучаю по твоим намерениям здесь.

  • '-'Как отмечалось ранее, это, вероятно, лучший вариант, как по смысловым, так и по практическим причинам.

  • Зависит от того, что вы подразумеваете под «неопределенным». 'X'технически "неизвестно". 'U'предназначен для неинициализированных сигналов, которые ModelSim отображает как "X"для шестнадцатеричных представлений. 'X'кажется, работает, хотя, как я отметил выше.

Другой альтернативой было бы сделать оптимизацию самостоятельно и убрать один случай из явного тестирования:

if instruction(15 downto 8) = "11111001" then
  write_data <= std_ulogic_vector(resize(signed(instruction(7 downto 4)), 16));
else
  write_data <= std_ulogic_vector(resize(signed(instruction(7 downto 0)), 16));
end if;

Однако это имеет существенные недостатки (в основном связанные с ясностью кода), и я, вероятно, выбрал бы более идеальное решение.

Кстати, '-'также часто используется с std_match(), который я хотел бы использовать для вашего декодирования, например:

if std_match(instruction(15 downto 8), "1100----") then

Хотя в этот момент вам, вероятно, лучше просто использовать case?.

fru1tbat
источник
6

Короче говоря, это законный VHDL и обычно поддерживается инструментами синтеза.

Однако довольно редко можно увидеть его использование. Я действительно не знаю почему. Ваш код кажется мне хорошим примером того, когда было бы целесообразно использовать его.

Однако есть один недостаток, о котором следует помнить: при синтезе функции, приводящие к выводам, в которые не обращают внимания, могут отличаться между прогонами синтеза. Это делает синтез менее детерминированным. Если используются выходные данные, которые были определены как все равно (по ошибке), это может затруднить поиск ошибки.

Поддержка инструмента

По крайней мере, следующие инструменты примут все заботы и используют возможности оптимизации:

  • Xilinx (см .: «Руководство пользователя XST»)
  • Altera (ссылка: «Рекомендуемые стили кодирования HDL»)
  • Synplify (см .: «Справочное руководство Synplify»)

Xilinx и Altera будут лечить, '-'и, 'X'как им все равно, Synplify будет лечить их, а тем более 'U'и 'W'(слабых), как все равно.

деревенщина
источник
1
У меня было еще одно применение этого недостатка. Код работал в симуляции, но не на FPGA, потому что мой код выглядит вот так: if signal = '1' then a; else b; end if;. К сожалению, signalне было 1или 0но -. Таким образом, в симуляции elseветвь была выполнена, но в аппаратной части -оказалась 1, так что истинная ветвь была выполнена ...
Фриц
Да, у меня были похожие ошибки прохождения симуляции, но чаще всего в моем случае встречаются 'U's, общие в начале симуляции, которые приводят к выполнению некоторого elseблока кода. Было бы замечательно, если бы можно было как-то сделать условные 'U'выражения для распространения s, подобно поведению одновременных логических выражений.
Карл
После того, как я обнаружил эту ошибку, я всегда писал что-то вроде if signal = '1' then output <= '1'; elsif signal='0' then output <= '0'; else output <= '-'; end if;. И я добавил следующее ко всем регистрам и воспоминаниям: assert not is_X(write_enable) report "we=" & str(A_write_enable) severity ERROR;и if write_enable = '1' then assert not is_X(write_addr) report "write_addr=str(write_addr) severity ERROR; end if;. Плюс тоже самое write_data. Вместе, это должно поймать почти все эти ошибки.
Фриц
Это способ, но это слишком многословно для меня. Я хотел бы получить такую ​​возможность на языке VHDL.
Карл
1
Ну да, VHDL немного многословен, но это только способ VHDL. : D С другой стороны, это также очень явно, и не делает "черной магии" за моей спиной, что я нахожу довольно хорошим (см. Zen of Python "Явное лучше, чем неявное").
Фриц