На курсах «Логическое проектирование» мы все узнали, что можно минимизировать логическую функцию, например, используя карту Карно или алгоритм Куайна – МакКласки . Мы также узнали, что значения «Не волнует» увеличивают потенциал минимизации.
Например возьмите файл реестра. write_address
И write_data
сигналы на самом деле не имеет значения , когда write_enable
сигнал '0'
. Таким образом, им должно быть присвоено значение «Не заботиться», чтобы позволить больше оптимизаций в логике, управляющей этими сигналами (т.е. не в самом файле регистра).
Как правильно указать такие значения «Не волнует» в VHDL, чтобы предоставить инструменту синтеза больше места для возможных оптимизаций?
До сих пор я нашел следующие вещи, которые могут быть подходящими. Но я не совсем уверен, каковы плюсы и минусы каждого подхода:
- Просто не присваивать сигнал. Кажется, это может сработать. Однако я обнаружил, что это не работает, когда вы хотите определить константу «ничего не делать» некоторого
record
типа, поскольку константы записи должны быть полностью определены (по крайней мере, Modelsim говорит мне об этом). std_logic_1164
Пакет определяет значение'-' -- Don't care
дляstd_ulogic
. Похоже, что это семантически правильный выбор для явного «пофиг», но я никогда не видел, чтобы он использовался где-либо (кроме несвязанных конструкций VHDL-2008case?
).- 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
? Какую оптимизацию вы ожидаете провести?Ответы:
Я оставлю это на усмотрение эксперта по LRM, чтобы дать более подробный ответ, но вкратце, ваш подход должен быть верным - я провел быстрый тест с последней версией Quartus, и он обрабатывает,
'-'
как и положено - сгенерированная логика сокращена как и следовало ожидать, когда выход по умолчанию'-'
('X'
тоже работает, кстати). Подробнее о подходах, которые вы перечислили:Конечно, если вы не хотите использовать защелки, не назначайте сигнал для вашего примера. Если это синхронизированный процесс, вам будет немного лучше, но вы все равно получите разрешения там, где они могут вам не понадобиться. Может быть, я скучаю по твоим намерениям здесь.
'-'
Как отмечалось ранее, это, вероятно, лучший вариант, как по смысловым, так и по практическим причинам.Зависит от того, что вы подразумеваете под «неопределенным».
'X'
технически "неизвестно".'U'
предназначен для неинициализированных сигналов, которые ModelSim отображает как"X"
для шестнадцатеричных представлений.'X'
кажется, работает, хотя, как я отметил выше.Другой альтернативой было бы сделать оптимизацию самостоятельно и убрать один случай из явного тестирования:
Однако это имеет существенные недостатки (в основном связанные с ясностью кода), и я, вероятно, выбрал бы более идеальное решение.
Кстати,
'-'
также часто используется сstd_match()
, который я хотел бы использовать для вашего декодирования, например:Хотя в этот момент вам, вероятно, лучше просто использовать
case?
.источник
Короче говоря, это законный VHDL и обычно поддерживается инструментами синтеза.
Однако довольно редко можно увидеть его использование. Я действительно не знаю почему. Ваш код кажется мне хорошим примером того, когда было бы целесообразно использовать его.
Однако есть один недостаток, о котором следует помнить: при синтезе функции, приводящие к выводам, в которые не обращают внимания, могут отличаться между прогонами синтеза. Это делает синтез менее детерминированным. Если используются выходные данные, которые были определены как все равно (по ошибке), это может затруднить поиск ошибки.
Поддержка инструмента
По крайней мере, следующие инструменты примут все заботы и используют возможности оптимизации:
Xilinx и Altera будут лечить,
'-'
и,'X'
как им все равно, Synplify будет лечить их, а тем более'U'
и'W'
(слабых), как все равно.источник
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
. Вместе, это должно поймать почти все эти ошибки.