首页 > 解决方案 > 如何减少 VHDL 设计中的 ALM 数量?

问题描述

我正在尝试用 VHDL 实现数字时钟的报警模块。我已经为它编写了架构,但是当我运行编译时,我得到了太多的自适应逻辑模块(大约 2000 年),我认为这太多了。我将在下面发布我的代码。

在这行代码中,我认为除法和模运算可能会导致它。

alarm_hour1   <= std_logic_vector(to_unsigned(savedHours/10,alarm_hour1'length)); 
alarm_hour0   <= std_logic_vector(to_unsigned(savedHours mod 10,alarm_hour0'length));      
alarm_minute1 <= std_logic_vector(to_unsigned(savedMinutes/10,alarm_minute1'length));     
alarm_minute0 <= std_logic_vector(to_unsigned(savedMinutes mod 10,alarm_minute0'length));

不过,我不确定如何解决这个问题。

另外,如果您对我的设计提出更多意见,并指出一些错误,以及如何改进我的设计,我将不胜感激。我对 VHDL 相当陌生,所以任何建议都值得赞赏。

非常感谢。

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

entity alarm is
port(
    --INPUTS
    reset                         : in std_logic;
    clock                     : in std_logic;
    alarm_enable              : in std_logic;
    alarm_set              : in std_logic;
    alarm_increment        : in std_logic;
    alarm_decrement        : in std_logic;
    currentTime_hour1      : in std_logic_vector(3 downto 0);
    currentTime_hour0      : in std_logic_vector(3 downto 0);
    currentTime_minute1   : in std_logic_vector(3 downto 0);
    currentTime_minute0    : in std_logic_vector(3 downto 0);
    
    --OUTPUTS
    alarm_buzzer              : out std_logic;
    alarm_hour1             : buffer std_logic_vector(3 downto 0) := "0000";
    alarm_hour0            : buffer std_logic_vector(3 downto 0) := "0000";
    alarm_minute1          : buffer std_logic_vector(3 downto 0) := "0000";
    alarm_minute0          : buffer std_logic_vector(3 downto 0) := "0000"
);
end alarm;

architecture alarmBehaviour of alarm is
--ALARM TIME
signal savedHours   : integer := 0;
signal savedMinutes : integer := 0;

signal incrementDecrementbuttonDetect : std_logic;

signal set_lastButtonState  : std_logic := '0';
signal setButtonDetect     : std_logic := '0';

--STATE MACHINE
type state_type is (idle, setHour, setMinute);
signal state_reg, state_next : state_type;

begin
incrementDecrementbuttonDetect <= alarm_increment or alarm_decrement;

--STATE REGISTER
process(clock, reset)
begin
    if (reset = '1') then
        state_reg <= idle;
    elsif rising_edge(clock) then
        state_reg <= state_next;
    end if;
end process;


--SET BUTTON PRESSED
process(clock)
begin
if(rising_edge(clock)) then
    if(alarm_set = '1' and set_lastButtonState = '0') then
        setButtonDetect <= '1';
    else
        setButtonDetect <= '0';
    end if;
    set_lastButtonState <= alarm_set;
end if;
end process;

--NEXT STATE
process(state_reg, setButtonDetect)
begin
    case state_reg is
        when idle =>
            if setButtonDetect = '1' then
                state_next <= setHour;
            else
                state_next <= idle;
            end if;
            
        when setHour =>
            if setButtonDetect = '1' then
                state_next <= setMinute;
            else
                state_next <= setHour;
            end if;
            
        when setMinute =>
            if setButtonDetect = '1' then
                state_next <= idle;
            else
                state_next <= setMinute;
            end if;
    end case;
end process;

process (incrementDecrementbuttonDetect, state_reg)
begin
    if rising_edge(incrementDecrementbuttonDetect) then
        case state_reg is
            when idle =>
            when setHour =>
                if alarm_increment = '1' then
                    if savedHours = 23 then
                        savedHours <= 0;
                    else
                        savedHours <= savedHours + 1;
                    end if;
                else null;
                end if;
                
                if alarm_decrement = '1' then
                    if savedHours = 0 then
                        savedHours <= 23;
                    else
                        savedHours <= savedHours - 1;
                    end if;
                else null;
                end if;
                
            when setMinute =>
                if alarm_increment = '1' then
                    if savedMinutes = 59 then
                        savedMinutes <= 0;
                    else
                        savedMinutes <= savedMinutes + 1;
                    end if;
                else null;
                end if;
                
                if alarm_decrement = '1' then
                    if savedMinutes = 0 then
                        savedMinutes <= 59;
                    else
                        savedMinutes <= savedMinutes - 1;
                    end if;
                else null;
                end if;
        end case;
    end if;

end process;
    
alarm_hour1   <= std_logic_vector(to_unsigned(savedHours/10,alarm_hour1'length)); 
alarm_hour0   <= std_logic_vector(to_unsigned(savedHours mod 10,alarm_hour0'length));      
alarm_minute1 <= std_logic_vector(to_unsigned(savedMinutes/10,alarm_minute1'length));     
alarm_minute0 <= std_logic_vector(to_unsigned(savedMinutes mod 10,alarm_minute0'length));

--ALARM BUZZER CONDITION
process (currentTime_hour1, currentTime_hour0, currentTime_minute1, currentTime_minute0, 
alarm_enable, alarm_hour1, alarm_hour0, alarm_minute1, alarm_minute0)
begin
    if((alarm_hour1 = currentTime_hour1) and (alarm_hour0 = currentTime_hour0) 
    and (alarm_minute1 = currentTime_minute1) and (alarm_minute0 = currentTime_minute0) and alarm_enable = '1')  then
        alarm_buzzer <= '1';
    else
        alarm_buzzer <= '0';
    end if;
end process;
end alarmBehaviour;

标签: vhdlfpgaintel-fpga

解决方案


信号的范围savedHourssavedMinutes没有指定,所以 Quartus 假设它们是 32 位宽的。用一个 32 位操作数推断除法器会产生一棵大的条件减法树。

将您的代码更新为类似

--ALARM TIME
signal savedHours   : natural range 0 to 23 := 0;
signal savedMinutes : natural range 0 to 59 := 0;

很可能会导致更少的 ALM 使用。

另外,请注意,它rising_edge只能用于时钟信号(在 VHDL 入门级)。您可能需要一些按钮去抖动逻辑,而不是将逻辑连接到寄存器的时钟输入。


推荐阅读