如何在不创建新输入信号的情况下编写具有多个输入的多路复用器?
How to Write A Mux With Several Inputs Without Creating a New Input Signal?
如果无法做到这一点,请给我一个简单的 "no" 以及一个简短的答案来说明原因,但我只是想仔细检查一下这是否无法完成。
我有这个过程:
process(clk_p)
begin
if rising_edge(clk_p) then
if rst_i = '1' then
stored_events <= (others => '0');
else
if mode_triggered = '1' and ptr = 0 and read_state = ST_ENABLE then
stored_events <= stored_events;
elsif mode_triggered = '1' then
stored_events <= stored_events + 1;
elsif ptr = 0 and read_state = ST_ENABLE then
stored_events <= stored_events - 1;
end if;
end if;
end if;
end process;
是的,这不是很好,这就是为什么我要通过将它变成一个合适的 case mux 来帮助合成。
你可以这样做:
sel(0) <= '1' when mode_triggered= = '1' else '0';
sel(1) <= '1' when ptr = 1 else '0';
sel(2) <= '1' when read_state = ST_ENABLE else '0';
case sel is
when "111" =>
stored_events <= stored_events; -- and so on...
虽然我要更改几个进程,但我想创建更多的信号名称。所以...
我想知道是否有一些我喜欢的方法(虽然不完全确定最终的 when others
会怎样):
case mode_triggered, ptr, read_state is
when '1', 0, ST_ENABLE =>
stored_events <= stored_events;
您可能可以使用记录 and/or VHDL-2008 语法实现您想要的,但我建议不要这样做。
你不仅会失去可读性,我严重怀疑你是否会获得任何综合增益。
当我查看您的代码时,我没有看到任何多路复用器。相反,我看到一个带有同步复位和时钟使能端口的 up/down 计数器。如果你愿意,你可以这样写:
clk_en <= '0' when mode_triggered = '1' and ptr = 0 and read_state = ST_ENABLE else
'1' when mode_triggered = '1' or (ptr = 0 and read_state = ST_ENABLE) else
'0';
up <= '1' when mode_triggered = '1' else '0';
process(clk_p)
begin
if rising_edge(clk_p) then
if rst_i = '1' then
stored_events <= (others => '0');
elsif clk_en = '1' then
if up = '1' then
stored_events <= stored_events + 1;
else
stored_events <= stored_events - 1;
end if;
end if;
end if;
end process;
所有三种编写代码的方式都应该导致相同的网表(希望如此),它们只是可读性不同。就个人而言,我更喜欢你的第一次尝试,因为它来自你正在实现的 function,但它都是首选。我也不喜欢 mux 方法(对于这种情况)。
根据经验,不要写信给 help 合成器,除非你也有。查看综合报告和生成的网表,仅当您不喜欢所看到的内容时才进行调整。与我们人类理解充满多路复用器和逻辑门的代码的功能相比,合成器更擅长从您第一次尝试的代码中提取电路。
另一种变体(向上和向下是布尔值)可能有助于提高可读性
down <= ptr = 0 and read_state = ST_ENABLE;
up <= mode_triggered and not down;
process(clk_p)
begin
if rising_edge(clk_p) then
if rst_i = '1' then
stored_events <= (others => '0');
else
if up then
stored_events <= stored_events + 1;
elsif down then
stored_events <= stored_events - 1;
end if;
end if;
end if;
end process;
如果无法做到这一点,请给我一个简单的 "no" 以及一个简短的答案来说明原因,但我只是想仔细检查一下这是否无法完成。
我有这个过程:
process(clk_p)
begin
if rising_edge(clk_p) then
if rst_i = '1' then
stored_events <= (others => '0');
else
if mode_triggered = '1' and ptr = 0 and read_state = ST_ENABLE then
stored_events <= stored_events;
elsif mode_triggered = '1' then
stored_events <= stored_events + 1;
elsif ptr = 0 and read_state = ST_ENABLE then
stored_events <= stored_events - 1;
end if;
end if;
end if;
end process;
是的,这不是很好,这就是为什么我要通过将它变成一个合适的 case mux 来帮助合成。
你可以这样做:
sel(0) <= '1' when mode_triggered= = '1' else '0';
sel(1) <= '1' when ptr = 1 else '0';
sel(2) <= '1' when read_state = ST_ENABLE else '0';
case sel is
when "111" =>
stored_events <= stored_events; -- and so on...
虽然我要更改几个进程,但我想创建更多的信号名称。所以...
我想知道是否有一些我喜欢的方法(虽然不完全确定最终的 when others
会怎样):
case mode_triggered, ptr, read_state is
when '1', 0, ST_ENABLE =>
stored_events <= stored_events;
您可能可以使用记录 and/or VHDL-2008 语法实现您想要的,但我建议不要这样做。
你不仅会失去可读性,我严重怀疑你是否会获得任何综合增益。
当我查看您的代码时,我没有看到任何多路复用器。相反,我看到一个带有同步复位和时钟使能端口的 up/down 计数器。如果你愿意,你可以这样写:
clk_en <= '0' when mode_triggered = '1' and ptr = 0 and read_state = ST_ENABLE else
'1' when mode_triggered = '1' or (ptr = 0 and read_state = ST_ENABLE) else
'0';
up <= '1' when mode_triggered = '1' else '0';
process(clk_p)
begin
if rising_edge(clk_p) then
if rst_i = '1' then
stored_events <= (others => '0');
elsif clk_en = '1' then
if up = '1' then
stored_events <= stored_events + 1;
else
stored_events <= stored_events - 1;
end if;
end if;
end if;
end process;
所有三种编写代码的方式都应该导致相同的网表(希望如此),它们只是可读性不同。就个人而言,我更喜欢你的第一次尝试,因为它来自你正在实现的 function,但它都是首选。我也不喜欢 mux 方法(对于这种情况)。
根据经验,不要写信给 help 合成器,除非你也有。查看综合报告和生成的网表,仅当您不喜欢所看到的内容时才进行调整。与我们人类理解充满多路复用器和逻辑门的代码的功能相比,合成器更擅长从您第一次尝试的代码中提取电路。
另一种变体(向上和向下是布尔值)可能有助于提高可读性
down <= ptr = 0 and read_state = ST_ENABLE;
up <= mode_triggered and not down;
process(clk_p)
begin
if rising_edge(clk_p) then
if rst_i = '1' then
stored_events <= (others => '0');
else
if up then
stored_events <= stored_events + 1;
elsif down then
stored_events <= stored_events - 1;
end if;
end if;
end if;
end process;