Hi, I’m not quite sure if this vhdl code and testbench is correct for the given task. Can you take a look?

Design a one-hour kitchen timer. The device should have buttons/switches to start and stop the timer, as well as to set the desired time interval for the alarm. Realize the task using the software package Quartus or in GHDL, confirm the correctness of the project task by simulation.

This is VHDL code:

use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Kitchen_Timer is
  port (
    clk   : in std_logic;    -- Clock input
    reset : in std_logic;    -- Reset input
    start : in std_logic;    -- Start button input
    stop  : in std_logic;    -- Stop button input
    alarm : out std_logic    -- Alarm output
  );
end entity Kitchen_Timer;

-- Declare the architecture for the kitchen timer
architecture Behavioral of Kitchen_Timer is
  signal count     : integer range 0 to 3600 := 0;   -- Counter for timer
  signal alarming  : std_logic := '0';               -- Signal to indicate alarming interval
  signal alarm_en  : std_logic := '0';               -- Signal to enable alarming interval
  signal alarm_cnt : integer range 0 to 600 := 0;    -- Counter for alarming interval
begin
  -- Process to control the kitchen timer and alarming interval
  process (clk, reset)
  begin
    if (reset = '1') then
      count     <= 0;
      alarming  <= '0';
      alarm_en  <= '0';
      alarm_cnt <= 0;
    elsif (rising_edge(clk)) then
      if (stop = '1') then
        count     <= 0;
        alarming  <= '0';
        alarm_en  <= '0';
        alarm_cnt <= 0;
      elsif (start = '1' and count < 3600) then
        count <= count + 1;
        if (count = 3600) then
          count     <= 0;
          alarming  <= '0';
          alarm_en  <= '0';
          alarm_cnt <= 0;
        elsif (count > 0) then
          alarm_en <= '1';
        end if;
      end if;

      if (alarm_en = '1') then
        if (alarm_cnt < 600) then
          alarm_cnt <= alarm_cnt + 1;
        else
          alarm_cnt <= 0;
          alarming  <= '1';
        end if;
      end if;
    end if;
  end process;

  -- Assign the alarm output
  alarm <= alarming;
end architecture Behavioral; ```

This is Testbench:

```library ieee;
use ieee.std_logic_1164.all;

entity tb_Kitchen_Timer is
end tb_Kitchen_Timer;

architecture tb of tb_Kitchen_Timer is

    component Kitchen_Timer
        port (clk   : in std_logic;
              reset : in std_logic;
              start : in std_logic;
              stop  : in std_logic;
              alarm : out std_logic);
    end component;

    signal clk   : std_logic;
    signal reset : std_logic;
    signal start : std_logic;
    signal stop  : std_logic;
    signal alarm : std_logic;

    constant TbPeriod : time := 1000 ns; -- EDIT Put right period here
    signal TbClock : std_logic := '0';
    signal TbSimEnded : std_logic := '0';

begin

    dut : Kitchen_Timer
    port map (clk   => clk,
              reset => reset,
              start => start,
              stop  => stop,
              alarm => alarm);

    -- Clock generation
    TbClock <= not TbClock after TbPeriod/2 when TbSimEnded /= '1' else '0';

    -- EDIT: Check that clk is really your main clock signal
    clk <= TbClock;

    stimuli : process
    begin
        -- EDIT Adapt initialization as needed
        start <= '0';
        stop <= '0';

        -- Reset generation
        -- EDIT: Check that reset is really your reset signal
        reset <= '1';
        wait for 100 ns;
        reset <= '0';
        wait for 100 ns;

        -- EDIT Add stimuli here
        wait for 100 * TbPeriod;

        -- Stop the clock and hence terminate the simulation
        TbSimEnded <= '1';
        wait;
    end process;

end tb;

-- Configuration block below is required by some simulators. Usually no need to edit.

configuration cfg_tb_Kitchen_Timer of tb_Kitchen_Timer is
    for tb
    end for;
end cfg_tb_Kitchen_Timer;```

 #science

  • T4V0@kbin.social
    link
    fedilink
    arrow-up
    1
    ·
    edit-2
    1 year ago

    @dejo This is much better, but there is still some room for improvement.

    There is a mismatch between your comparisons count and alarm_interval. Here in the code bellow you can see the issue:

    if stop = '1' or count = alarm_interval then
    
    count &lt;= 0; -- count is 0 here
    
    end if;
    
    [...]
    
    alarming &lt;= '1' when count >= alarm_interval else '0'; -- This condition is never true due to count always being 0 or smaller the alarm_interval.
    alarm &lt;= alarming;
    
    

    As it is right now, the alarming signal is never going to be ‘1’. It is best to split the comparison and write to alarming directly:

    if stop = '1' then
    
    count &lt;= 0;
    alarming &lt;= '0';
    
    end if;
    
    if count = alarm_interval then
    
    alarming &lt;= '1';
    
    end if;
    
    [...]
    
    alarm &lt;= alarming
    
    

    As for the testbench, you should set the start and unset it only after the alarming is ‘1’, and test if alarming is working after adjusting the timer:

    stimuli : process
    
    begin
    
    -- Reset generation
    
    reset &lt;= '1';
    
    wait for 20 us; -- Adjust delay to fit the new clock period
    
    reset &lt;= '0';
    
    -- Add your stimuli and test cases here
    
    -- For example:
    
    start &lt;= '1';
    stop &lt;= '0';
    
    wait for 620 us; -- Wait until alarm is alarming
    
    start &lt;= '0'
    stop &lt;= '1';
    adjust_interval_up &lt;= '1';
    
    wait for 1 us; -- Increment the timer by a minute
    
    start &lt;= '1';
    stop &lt;= '0';
    adjust_interval_up &lt;= '0';
    
    wait for 1220 us; -- Wait until the alarm is alarming
    
    start &lt;= '0';
    stop &lt;= '1';
    adjust_interval_down &lt;= '1';
    
    wait for 1 us; -- Decrement the timer by a minute
    
    start &lt;= '1';
    stop &lt;= '0';
    adjust_interval_down &lt;= '0';
    
    wait for 620 us; -- Wait until the alarm is alarming
    
    start &lt;= '0';
    stop &lt;= '1';
    
    wait for 20 us;
    
    -- ...
    
    -- Stop the clock and hence terminate the simulation
    
    TbSimEnded &lt;= '1';
    
    wait;
    
    end process;
    
    

    I suggest changing the 100 ms time slices you use in the timer to a minute instead. That way your simulation time could be much quicker (though you would also have to change the testbench delays).

    • dejo@kbin.socialOP
      link
      fedilink
      arrow-up
      2
      ·
      edit-2
      1 year ago

      @T4V0 I
      In the meantime, I worked on improving the code.

      VHDL code:
      llibrary ieee;
      use ieee.std_logic_1164.all;
      use ieee.numeric_std.all;

      entity Kitchen_Timer is
      port (
      clk : in std_logic; – Clock input
      reset : in std_logic; – Reset input
      start : in std_logic; – Start button input
      stop : in std_logic; – Stop button input
      adjust_interval_up : in std_logic; – Button for increasing alarm interval
      adjust_interval_down : in std_logic; – Button for decreasing alarm interval
      alarm : out std_logic – Alarm output
      );
      end entity Kitchen_Timer;
      architecture Behavioral of Kitchen_Timer is
      signal count : integer range 0 to 3600000 := 0; – Adjust range for 1 hour
      signal alarming : std_logic := ‘0’;
      signal alarm_interval : integer range 600 to 3600000 := 600; – Adjust range for 1 hour
      begin
      process (clk, reset)
      begin
      if reset = ‘1’ then
      count &lt;= 0;
      alarm_interval &lt;= 600;
      elsif rising_edge(clk) then
      if start = ‘1’ then
      count &lt;= count + 1;
      end if;
      if stop = ‘1’ or count = alarm_interval then
      count &lt;= 0;
      end if;
      if adjust_interval_up = ‘1’ then
      if alarm_interval &lt; 3600000 then
      alarm_interval &lt;= alarm_interval + 600; – Adjust increment for 1 minute
      end if;
      count &lt;= 0; – Reset count when adjusting interval
      elsif adjust_interval_down = ‘1’ then
      if alarm_interval > 600 then
      alarm_interval &lt;= alarm_interval - 600; – Adjust decrement for 1 minute
      end if;
      count &lt;= 0; – Reset count when adjusting interval
      end if;
      end if;
      end process;
      alarming &lt;= ‘1’ when count >= alarm_interval else ‘0’;
      alarm &lt;= alarming;
      end architecture Behavioral;

      Testbench:

      library ieee;
      use ieee.std_logic_1164.all;

      entity tb_Kitchen_Timer is
      end tb_Kitchen_Timer;
      architecture tb of tb_Kitchen_Timer is
      component Kitchen_Timer
      port (
      clk : in std_logic;
      reset : in std_logic;
      start : in std_logic;
      stop : in std_logic;
      adjust_interval_up : in std_logic;
      adjust_interval_down : in std_logic;
      alarm : out std_logic
      );
      end component;
      signal clk : std_logic := ‘0’;
      signal reset : std_logic := ‘0’;
      signal start : std_logic := ‘0’;
      signal stop : std_logic := ‘0’;
      signal adjust_interval_up : std_logic := ‘0’;
      signal adjust_interval_down : std_logic := ‘0’;
      signal alarm : std_logic;
      constant TbPeriod : time := 20 ns;
      signal TbClock : std_logic := ‘0’;
      signal TbSimEnded : std_logic := ‘0’;
      begin
      dut : Kitchen_Timer
      port map (
      clk => clk,
      reset => reset,
      start => start,
      stop => stop,
      adjust_interval_up => adjust_interval_up,
      adjust_interval_down => adjust_interval_down,
      alarm => alarm
      );
      -- Clock generation
      TbClock &lt;= not TbClock after TbPeriod/2 when TbSimEnded /= ‘1’ else ‘0’;
      clk &lt;= TbClock;
      stimuli : process
      variable num_ticks : natural;
      begin
      -- Reset generation
      reset &lt;= ‘1’;
      wait for 200 us;
      reset &lt;= ‘0’;
      wait for 200 us;
      -- Start the timer
      start &lt;= ‘1’;
      wait for 500 us;
      -- Adjust interval up and down
      adjust_interval_up &lt;= ‘1’;
      wait for 100 us;
      adjust_interval_up &lt;= ‘0’;
      wait for 100 us;
      adjust_interval_down &lt;= ‘1’;
      wait for 100 us;
      adjust_interval_down &lt;= ‘0’;
      wait for 100 us;
      -- Wait for the timer to reach the alarm interval (3600000 clocks)
      wait for 72 ms; – Simulate for the required time
      -- Stop the timer
      start &lt;= ‘0’;
      wait for 300 us;
      -- Stop the clock and terminate the simulation
      TbSimEnded &lt;= ‘1’;
      wait;
      end process;
      end tb;

      And this is simulation:

      • T4V0@kbin.social
        link
        fedilink
        arrow-up
        1
        ·
        1 year ago

        @dejo I have made a few changes to your code:

        Kitchen_Timer.vhd

        library ieee;
        use ieee.std_logic_1164.all;
        use ieee.numeric_std.all;
        
        entity Kitchen_Timer is
            port
            (
                clk                  : in std_logic; -- Clock input
                reset                : in std_logic; -- Reset input
                start                : in std_logic; -- Start button input
                stop                 : in std_logic; -- Stop button input
                adjust_interval_up   : in std_logic; -- Button for increasing alarm interval
                adjust_interval_down : in std_logic; -- Button for decreasing alarm interval
                alarm                : out std_logic -- Alarm output
            );
        end entity Kitchen_Timer;
        architecture Behavioral of Kitchen_Timer is
            signal count          : integer range 0 to 60 := 0; -- Adjust range for 1 hour
            signal alarming       : std_logic             := '0';
            signal alarm_interval : integer range 1 to 60 := 1; -- Adjust range for 1 hour
        begin
            process (clk, reset)
            begin
                if reset = '1' then
                    count          &lt;= 0;
                    alarm_interval &lt;= 1;
                elsif rising_edge(clk) then
                    if start = '1' then
                        count &lt;= count + 1;
                    end if;
                    if stop = '1' then
                        count    &lt;= 0;
                        alarming &lt;= '0';
                    end if;
                    if count = alarm_interval then
                        alarming &lt;= '1';
                    end if;
                    if adjust_interval_up = '1' then
                        if alarm_interval &lt; 60 then
                            alarm_interval &lt;= alarm_interval + 1; -- Adjust increment for 1 minute
                        end if;
                        count &lt;= 0; -- Reset count when adjusting interval
                    elsif adjust_interval_down = '1' then
                        if alarm_interval > 60 then
                            alarm_interval &lt;= alarm_interval - 1; -- Adjust decrement for 1 minute
                        end if;
                        count &lt;= 0; -- Reset count when adjusting interval
                    end if;
                end if;
            end process;
            alarm &lt;= alarming;
        end architecture Behavioral;
        
        

        tb_Kitchen_Timer.vhd

        library ieee;
        use ieee.std_logic_1164.all;
        use ieee.numeric_std.all;
        
        entity tb_Kitchen_Timer is
        end tb_Kitchen_Timer;
        
        architecture tb of tb_Kitchen_Timer is
            signal clk                  : std_logic := '0';
            signal reset                : std_logic := '0';
            signal start                : std_logic := '0';
            signal stop                 : std_logic := '0';
            signal adjust_interval_up   : std_logic := '0';
            signal adjust_interval_down : std_logic := '0';
            signal alarm                : std_logic;
            constant TbPeriod           : time      := 10 ns;
            signal TbClock              : std_logic := '0';
            signal TbSimEnded           : std_logic := '0';
        begin
            dut : entity work.Kitchen_Timer
            port map
            (
                clk                  => clk,
                reset                => reset,
                start                => start,
                stop                 => stop,
                adjust_interval_up   => adjust_interval_up,
                adjust_interval_down => adjust_interval_down,
                alarm                => alarm
            );
        
            -- Clock generation
            TbClock &lt;= not TbClock after TbPeriod/2 when TbSimEnded /= '1' else '0';
        
            -- EDIT: Check that clk is really your main clock signal
            clk &lt;= TbClock;
        
            stimuli : process
                variable num_ticks : natural;
            begin
                -- Reset generation
                reset &lt;= '1';
                wait for 20 ns;
                reset &lt;= '0';
                wait for 20 ns;
                -- Start the timer
                start &lt;= '1';
                wait for 20 ns;
                start &lt;= '0';
                stop  &lt;= '1';
                -- Adjust interval up and down
                adjust_interval_up &lt;= '1';
                wait for 10 ns;
                start              &lt;= '1';
                stop               &lt;= '0';
                adjust_interval_up &lt;= '0';
                wait for 30 ns;
                start                &lt;= '0';
                stop                 &lt;= '1';
                adjust_interval_down &lt;= '1';
                wait for 10 ns;
                start                &lt;= '1';
                stop                 &lt;= '0';
                adjust_interval_down &lt;= '0';
                wait for 20 ns;
                start              &lt;= '0';
                stop               &lt;= '1';
                adjust_interval_up &lt;= '1';
                wait for 600 ns;
                start              &lt;= '1';
                stop               &lt;= '0';
                adjust_interval_up &lt;= '0';
                -- Wait for the timer to reach the alarm interval (60 clocks)
                wait for 600 ns; -- Simulate for the required time
                -- Stop the timer
                start &lt;= '0';
                stop  &lt;= '1';
                wait for 100 ns;
                -- Stop the clock and terminate the simulation
                TbSimEnded &lt;= '1';
                wait;
            end process;
        end tb;
        
        

        This should be easier to simulate, I’ve included a simulation done with Questa.

        • dejo@kbin.socialOP
          link
          fedilink
          arrow-up
          1
          ·
          edit-2
          1 year ago

          @T4V0 I just now see your messages, thank you…
          In the meantime, I made something like this…
          What do you think about the specifications that the project requires, should I stick to your code or should I add something from my own code?
          Does your simulation correspond to a time of 1 hour and should there be alarming on the simulation?

          Vhdl code:

          library ieee;
          use ieee.std_logic_1164.all;
          use ieee.numeric_std.all;
          entity Kitchen_Timer is
          port (
          clk : in std_logic; – Clock input
          reset : in std_logic; – Reset input
          start : in std_logic; – Start button input
          stop : in std_logic; – Stop button input
          adjust_interval_up : in std_logic; – Button for increasing alarm interval
          adjust_interval_down : in std_logic; – Button for decreasing alarm interval
          alarm : out std_logic – Alarm output
          );
          end entity Kitchen_Timer;
          architecture Behavioral of Kitchen_Timer is
          signal count : integer range 0 to 3600000 := 0; – Adjust range for 1 hour
          signal alarming : std_logic := ‘0’;
          signal alarm_interval : integer range 600 to 3600000 := 600; – Adjust range for 1 hour
          begin
          process (clk, reset)
          begin
          if reset = ‘1’ then
          count &lt;= 0;
          alarm_interval &lt;= 600;
          elsif rising_edge(clk) then
          if start = ‘1’ then
          count &lt;= count + 1;
          end if;
          if stop = ‘1’ or count = alarm_interval then
          count &lt;= 0;
          end if;
          if adjust_interval_up = ‘1’ then
          if alarm_interval &lt; 3600000 then
          alarm_interval &lt;= alarm_interval + 600; – Adjust increment for 1 minute
          end if;
          count &lt;= 0; – Reset count when adjusting interval
          elsif adjust_interval_down = ‘1’ then
          if alarm_interval > 600 then
          alarm_interval &lt;= alarm_interval - 600; – Adjust decrement for 1 minute
          end if;
          count &lt;= 0; – Reset count when adjusting interval
          end if;
          end if;
          end process;
          alarming &lt;= ‘1’ when count >= alarm_interval else ‘0’;
          alarm &lt;= alarming;
          end architecture Behavioral;

          Testbench:

          library ieee;
          use ieee.std_logic_1164.all;
          entity tb_Kitchen_Timer is
          end tb_Kitchen_Timer;
          architecture tb of tb_Kitchen_Timer is
          component Kitchen_Timer
          port (
          clk : in std_logic;
          reset : in std_logic;
          start : in std_logic;
          stop : in std_logic;
          adjust_interval_up : in std_logic;
          adjust_interval_down : in std_logic;
          alarm : out std_logic
          );
          end component;
          signal clk : std_logic := ‘0’;
          signal reset : std_logic := ‘0’;
          signal start : std_logic := ‘0’;
          signal stop : std_logic := ‘0’;
          signal adjust_interval_up : std_logic := ‘0’;
          signal adjust_interval_down : std_logic := ‘0’;
          signal alarm : std_logic;
          constant TbPeriod : time := 20 ns;
          signal TbClock : std_logic := ‘0’;
          signal TbSimEnded : std_logic := ‘0’;
          begin
          dut : Kitchen_Timer
          port map (
          clk => clk,
          reset => reset,
          start => start,
          stop => stop,
          adjust_interval_up => adjust_interval_up,
          adjust_interval_down => adjust_interval_down,
          alarm => alarm
          );
          -- Clock generation
          TbClock &lt;= not TbClock after TbPeriod/2 when TbSimEnded /= ‘1’ else ‘0’;
          clk &lt;= TbClock;
          stimuli : process
          variable num_ticks : natural;
          begin
          -- Reset generation
          reset &lt;= ‘1’;
          wait for 200 us;
          reset &lt;= ‘0’;
          wait for 200 us;
          -- Start the timer
          start &lt;= ‘1’;
          wait for 500 us;
          -- Adjust interval up and down
          adjust_interval_up &lt;= ‘1’;
          wait for 100 us;
          adjust_interval_up &lt;= ‘0’;
          wait for 100 us;
          adjust_interval_down &lt;= ‘1’;
          wait for 100 us;
          adjust_interval_down &lt;= ‘0’;
          wait for 100 us;
          -- Wait for the timer to reach the alarm interval (3600000 clocks)
          wait for 72 ms; – Simulate for the required time
          -- Stop the timer
          start &lt;= ‘0’;
          wait for 300 us;
          -- Stop the clock and terminate the simulation
          TbSimEnded &lt;= ‘1’;
          wait;
          end process;
          end tb;

          • T4V0@kbin.social
            link
            fedilink
            arrow-up
            1
            ·
            edit-2
            1 year ago

            @dejo

            What do you think about the specifications that the project requires, should I stick to your code or should I add something from my own code?

            I would stick to my code, your alarm isn’t going to work properly due to its comparisons as I mentioned in my previous comments. But if you want to improve the code I modified, you can change the adjust_interval_up and adjust_interval_down buttons to be synchronized to their own states rather than the clock (make their own process with their signals added to the signal sensitivity list and add an extra asynchronous condition to zero the counter on the original process). If you don’t make a change like this your alarm is going to take up to an hour to adjust its timer range.

            Does your simulation correspond to a time of 1 hour and should there be alarming on the simulation?

            Yes, if you have a 1/60 Hertz clock signal. And you must have alarming on the simulation as it is crucial to show that it works.

            • dejo@kbin.socialOP
              link
              fedilink
              arrow-up
              1
              ·
              edit-2
              1 year ago

              @T4V0
              Is the 1/60 Hz set somewhere or is it set in the code itself?
              When you say that I must have an “alarming” signal on the simulation, is it actually this “alarm” signal that is presented on the simulation or?
              And, do I need to have count signal in simulation?

              • T4V0@kbin.social
                link
                fedilink
                arrow-up
                1
                ·
                1 year ago

                @dejo

                Is the 1/60 Hz set somewhere or is it set in the code itself?

                You would set that on the testbench or on your synthesis code, but that is unnecessary, I only said that in case if you tested it on a actual FPGA. If you do that on your testbench, it would take a very long time to simulate.

                When you say that I must have an “alarming” signal on the simulation, is it actually this “alarm” signal that is presented on the simulation or?

                The alarm signal. The “alarming” is when the alarm signal is in a high logic state.

                And, do I need to have count signal in simulation?

                I wouldn’t say it’s mandatory, but it is a good addition to the simulation, keep it.