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