-1

I'm trying to implement an alarm module for the digital clock in VHDL. I have written architecture for it, but when I run Compilation I get too many Adaptive Logic Modules (around 2000), which I think is too much. I will post my code below.

I think division and modulus operation could be causing it, in this line of code.

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));

Still, I'm not sure how can I work around this.

Also, I would be very grateful if You give more comments on my design, and point out some mistakes, and ways how I can improve my design. I'm fairly new to VHDL so any advice is appreciated.

Thanks a lot.

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;
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574

2 Answers2

1

Consider keeping the alarm time in Binary-Coded Decimal (BCD) format instead of binary format, whereby you can compare it directly with the current time, that is provided in BCD format.

This is a good example of how using the appropriate internal data format can reduce the computational problem significantly, since you can simply eliminate the costly division and modulo operations by keeping just one data format (BCD) instead of mixing BCD and binary data formats.

Morten Zilmer
  • 15,586
  • 3
  • 30
  • 49
  • BCD data type in VHDL? I haven't heard of that. I did a google search on that, and I haven't found any results. Can you be more specific? Thanks. – Aleksandar Simonović Jan 15 '21 at 00:05
  • 1
    I put it in general terms on purpose, to avoid spoiling your homework and learning experience ;-) You are doing hardware here, and have all the screws and bolts in VHDL, but you must assemble it yourself. `std_logic_vector` of variable length can represent values, so just take some of those for your different value parts. – Morten Zilmer Jan 15 '21 at 06:46
  • 1
    Each clock digit can be a separate counter with ranges 0 to 2 for tens of hours, 0 to 9 for hours and minutes, 0 to 5 for tens of minutes. For display purposes their values can be expressed as BCD. A hardware description not relying on base 10 division not always supported in synthesis for implied complexity reasons aptly demonstrated here while some vendors might encourage non-hardware designers into larger devices instead. –  Jan 15 '21 at 14:31
1

The range of signals savedHours and savedMinutes is not specified, so Quartus assumes they are 32 bits wide. Inference of a divider with one 32-bit operand results into a large tree of conditional subtractions.

Updating your code to something like

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

will very likely result into less ALM usage.

Also, please note that rising_edge should be used for clock signals only (at VHDL starter level). Instead of connecting logic to the clock input of a register, what you probably want is some button debounce logic.