Публикую впервые, поэтому простите меня за любые синтаксические ошибки в форматировании переполнения стека. Я рассматриваю элегантный способ сжатия следующего кода if/elsif в цикл for. Я добавил дополнительную информацию в начале кода, чтобы он имел больше смысла:
-- all of this is declared within my modules package file.
type uart_buffer is record
tx_out_buf : one_byte; -- Tx output UART Buffer.
rx_out_buf : one_byte; -- Rx output UART Buffer.
tx_out_buf_ful : std_logic; -- Indicate if the tx output buffer is full.
rx_out_buf_ful : std_logic; -- Indicate if the rx output buffer is full.
sending : std_logic; -- Tx Output buffer is currently sending char.
end record uart_buffer;
type uart_arr is array(7 downto 0) of uart_buffer;
constant EMPTY_UART_BUFFER : uart_buffer := (
-- define all values of an empty UART Buffer
tx_out_buf => (others => '0'),
rx_out_buf => (others => '0'),
tx_out_buf_ful => '0',
rx_out_buf_ful => '0',
sending => '0'
);
-- This section is declared within my modules architecture.
signal start_sending_char : std_logic := '0'; -- send a character packet to the device
signal uart_buffer_arr : uart_arr := (others => EMPTY_UART_BUFFER);
-- This section is within a process in my module that is conditioned to the
-- rising of edge of my systems clock. This is what I am hoping to simplify:
if (start_sending_char = '0') then
if (uart_buffer_arr(7).tx_out_buf_ful = '1') and
(uart_buffer_arr(7).sending = '0')
then
-- Send out to CHAR fifo from line 7.
uart_buffer_arr(7).sending <= '1';
start_sending_char <= '1';
elsif (uart_buffer_arr(6).tx_out_buf_ful = '1') and
(uart_buffer_arr(6).sending = '0')
-- Send out to CHAR fifo from line 6.
uart_buffer_arr(6).sending <= '1';
start_sending_char <= '1';
elsif (uart_buffer_arr(5).tx_out_buf_ful = '1') and
(uart_buffer_arr(5).sending = '0')
-- Send out to CHAR fifo from line 5.
uart_buffer_arr(5).sending <= '1';
start_sending_char <= '1';
elsif (uart_buffer_arr(4).tx_out_buf_ful = '1') and
(uart_buffer_arr(4).sending = '0')
-- Send out to CHAR fifo from line 4.
uart_buffer_arr(4).sending <= '1';
start_sending_char <= '1';
elsif (uart_buffer_arr(3).tx_out_buf_ful = '1') and
(uart_buffer_arr(3).sending = '0')
-- Send out to CHAR fifo from line 3.
uart_buffer_arr(3).sending <= '1';
start_sending_char <= '1';
elsif (uart_buffer_arr(2).tx_out_buf_ful = '1') and
(uart_buffer_arr(2).sending = '0')
-- Send out to CHAR fifo from line 2.
uart_buffer_arr(2).sending <= '1';
start_sending_char <= '1';
elsif (uart_buffer_arr(1).tx_out_buf_ful = '1') and
(uart_buffer_arr(1).sending = '0')
-- Send out to CHAR fifo from line 1.
uart_buffer_arr(1).sending <= '1';
start_sending_char <= '1';
elsif (uart_buffer_arr(0).tx_out_buf_ful = '1') and
(uart_buffer_arr(0).sending = '0')
-- Send out to CHAR fifo from line 0.
uart_buffer_arr(0).sending <= '1';
start_sending_char <= '1';
else
-- No lines to send on.
null;
end if;
end if;
Можно ли переписать эту последовательность операторов if/elsif в цикле for примерно так?
for i in 7 downto 0 loop
-- Send out to CHAR fifo starting with highest priority line 7 down to 0
-- if CHAR fifo is ready to receive.
if (start_sending_char = '0') then
if (uart_buffer_arr(i).tx_out_buf_ful = '1') and
(uart_buffer_arr(i).sending = '0')
then
uart_buffer_arr(i).sending <= '1';
start_sending_char <= '1';
end if;
end if;
end loop;
Если вы пройдёте по телу своего вопроса «Можно ли эту последовательность операторов if/elsif переписать во что-то вроде этого…», то это вопрос «да» или «нет», который невозможно убедительно продемонстрировать без минимального воспроизводимого примера.. (Ответ будет «да», а вопросы «да/нет» не требуют объяснений.)
Если вы добавили условие выхода из цикла после соответствия одному из условий, ваш код должен иметь эквивалентное поведение. OTOH, ваша удача может измениться в зависимости от инструментов синтеза.
Дополнительный вопрос. Если два или более процессов записывают элементы сигнала, самый длинный статический префикс имени используется для определения драйверов в процессе (IEEE Std 1076-2008 14.7.2 Драйвер). Эффективное значение сигнала — это разрешенное значение всех драйверов и порты. В дополнение к нестатическому выбранному имени (i) также есть два разных процесса, записывающие uart_buffer_arr(x).sending
для статического x в 7 до 0. если только все назначения uart_buff_ar не находятся в одном процессе. Приведите минимально воспроизводимый пример, чтобы те, кто испытывает желание ответить, не торопились и могли фактически продемонстрировать решение.
(И я заметил это, пытаясь создать минимально воспроизводимый пример из ваших фрагментов.)
Я согласен с комментариями @user16145658 и @Jim Lewis. Но я дам вам ответ, поскольку это проблема, с которой я часто сталкиваюсь. Ваш вложенный elsif — это решение, которое имеет 3 недостатка:
Когда числа увеличиваются и вам нужно перебирать не от 0 до 7, а от 0 до 63 или больше, тогда вставка опечатки становится более вероятной, и вам придется моделировать каждую ветку, чтобы убедиться, что все работает. Это означает, что решение, которое легче пропустить (даже если существует много ветвей), будет лучшим решением. Я называю такое решение «правильным по конструкции».
Вложенный elsif всегда вызывает глубокие пути синхронизации. Причина в том, что все условия необходимо проверять одно за другим (последовательно), потому что есть приоритетный порядок. Последовательная проверка может вызвать проблемы с замыканием синхронизации при синтезе. поэтому было бы лучше реализовать решение, которое можно было бы проверять параллельно.
Вложенный elsif затрудняет читателю проверку, выполняется ли во всех ветвях одно и то же действие (только в другой очереди). Это означает, что другой человек, не знакомый с конструкцией, должен тщательно проверить каждую ветку вручную, чтобы получить знания, если в каждой ветви выполняется одно и то же действие.
Поэтому я бы переписал ваш код следующим образом:
process(uart_buffer_arr)
begin
for i in 7 downto 0 loop
-- At all queues the same check is performed (correct by construction):
send_request(i) <= uart_buffer_arr(i).tx_out_buf_ful and not uart_buffer_arr(i).sending;
end loop;
end process;
process (clk)
begin
if rising_edge(clk) then
if start_sending_char='0' then
-- parallel check instead of a serial one (correct by construction):
if send_request/=(send_request'range => '0') then
-- Short timing path for this signal:
start_sending_char <= '1';
end if;
for i in 7 downto 0 loop
-- nested "if" cannot be avoided here
if send_request(i)='1' then
-- The same action is performed at all queues (correct by construction).
uart_buffer_arr(i).sending <= '1';
exit; -- provides priority order
end if;
end loop;
-- ... additional code for resetting start_sending_char to 0
end if;
end process;
Элегантность – это субъективно, вопросы здесь должны быть объективными, здесь это будет: «Они эквивалентны?» или «Есть ли причина, по которой не следует производить замену?». Это можно проверить на минимально воспроизводимом примере , где вы можете задать вопрос о любых расхождениях в проверке. См. Как спросить. Обратите внимание, что ни объявление one_byte, ни предложение контекста, ни предложения использования не видны, а ваши фрагменты не могут быть проанализированы с помощью инструмента, совместимого со стандартом VHDL. Отсутствует оператор выхода для эмуляции выбора только одного условия оператора if в цикле for. Условный выход может заменить оператор if.