在 VHDL 中将 If/Elsif 语句压缩为单个 For 循环语句的优雅方法

问题描述 投票:0回答:1

第一次发帖,请原谅我在堆栈溢出格式中出现的任何语法错误。我正在寻找一种将以下 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;

可以在 for 循环中将 if/elsif 语句的序列重写为类似的内容吗?

         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; 
for-loop if-statement vhdl hdl
1个回答
0
投票

我同意@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;
            end if;
        end loop;

        -- ... additional code for resetting start_sending_char to 0

    end if;
end process;
© www.soinside.com 2019 - 2024. All rights reserved.