Элегантный способ сжатия операторов If/Elsif в один оператор цикла For в VHDL

Публикую впервые, поэтому простите меня за любые синтаксические ошибки в форматировании переполнения стека. Я рассматриваю элегантный способ сжатия следующего кода 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; 

Элегантность – это субъективно, вопросы здесь должны быть объективными, здесь это будет: «Они эквивалентны?» или «Есть ли причина, по которой не следует производить замену?». Это можно проверить на минимально воспроизводимом примере , где вы можете задать вопрос о любых расхождениях в проверке. См. Как спросить. Обратите внимание, что ни объявление one_byte, ни предложение контекста, ни предложения использования не видны, а ваши фрагменты не могут быть проанализированы с помощью инструмента, совместимого со стандартом VHDL. Отсутствует оператор выхода для эмуляции выбора только одного условия оператора if в цикле for. Условный выход может заменить оператор if.

user16145658 07.05.2024 02:53

Если вы пройдёте по телу своего вопроса «Можно ли эту последовательность операторов if/elsif переписать во что-то вроде этого…», то это вопрос «да» или «нет», который невозможно убедительно продемонстрировать без минимального воспроизводимого примера.. (Ответ будет «да», а вопросы «да/нет» не требуют объяснений.)

user16145658 07.05.2024 02:57

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

Jim Lewis 07.05.2024 05:13

Дополнительный вопрос. Если два или более процессов записывают элементы сигнала, самый длинный статический префикс имени используется для определения драйверов в процессе (IEEE Std 1076-2008 14.7.2 Драйвер). Эффективное значение сигнала — это разрешенное значение всех драйверов и порты. В дополнение к нестатическому выбранному имени (i) также есть два разных процесса, записывающие uart_buffer_arr(x).sending для статического x в 7 до 0. если только все назначения uart_buff_ar не находятся в одном процессе. Приведите минимально воспроизводимый пример, чтобы те, кто испытывает желание ответить, не торопились и могли фактически продемонстрировать решение.

user16145658 08.05.2024 02:30

(И я заметил это, пытаясь создать минимально воспроизводимый пример из ваших фрагментов.)

user16145658 08.05.2024 02:30
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я согласен с комментариями @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;

Другие вопросы по теме