Skip Navigation

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

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


  

You're viewing part of a thread.

Show Context
23 comments
  • @T4V0 Hello, I've been doing a lot of research on this project these days and I've brought the code to a better level, I hope... But I'm not sure if this simulation...

    This is VHDL code:
    library ieee;

    use ieee.stdlogic1164.all;

    use ieee.numericstd.all;

    entity KitchenTimer is

    port (

    clk : in stdlogic; -- Clock input

    reset : in stdlogic; -- Reset input

    start : in stdlogic; -- Start button input

    stop : in stdlogic; -- Stop button input

    adjustintervalup : in stdlogic; -- Button for increasing alarm interval

    adjustintervaldown : in stdlogic; -- Button for decreasing alarm interval

    alarm : out stdlogic -- Alarm output

    );

    end entity KitchenTimer;

    architecture Behavioral of KitchenTimer is

    signal count : integer range 0 to 3600000 := 0; -- Adjust range for 1 hour

    signal alarming : stdlogic := '0';

    signal alarminterval : integer range 600 to 3600000 := 600; -- Adjust range for 1 hour

    begin

    process (clk, reset)

    begin

    if reset = '1' then

    count lt;= 0;

    alarming lt;= '0';

    alarminterval lt;= 600;

    elsif risingedge(clk) then

    if start = '1' then

    count lt;= count + 1;

    end if;

    if stop = '1' or count = alarminterval then

    count lt;= 0;

    end if;

    if adjustintervalup = '1' then

    if alarminterval lt; 3600000 then

    alarminterval lt;= alarminterval + 600; -- Adjust increment for 1 minute

    end if;

    elsif adjustintervaldown = '1' then

    if alarminterval 600 then

    alarminterval lt;= alarminterval - 600; -- Adjust decrement for 1 minute

    end if;

    end if;

    end if;

    end process;

    alarming lt;= '1' when count = alarminterval else '0';

    alarm lt;= alarming;

    end architecture Behavioral;

    This is Testbench:
    library ieee;

    use ieee.stdlogic1164.all;

    entity tbKitchenTimer is

    end tbKitchenTimer;

    architecture tb of tbKitchenTimer is

    component KitchenTimer

    port (

    clk : in stdlogic;

    reset : in stdlogic;

    start : in stdlogic;

    stop : in stdlogic;

    adjustintervalup : in stdlogic;

    adjustintervaldown : in stdlogic;

    alarm : out stdlogic

    );

    end component;

    signal clk : stdlogic := '0';

    signal reset : stdlogic := '0';

    signal start : stdlogic := '0';

    signal stop : stdlogic := '0';

    signal adjustintervalup : stdlogic := '0';

    signal adjustintervaldown : stdlogic := '0';

    signal alarm : stdlogic;

    constant TbPeriod : time := 1 us; -- Set the clock period to 1us

    signal TbClock : stdlogic := '0';

    signal TbSimEnded : stdlogic := '0';

    begin

    dut : KitchenTimer

    port map (

    clk = clk,

    reset = reset,

    start = start,

    stop = stop,

    adjustintervalup = adjustintervalup,

    adjustintervaldown = adjustintervaldown,

    alarm = alarm

    );

    - Clock generation

    TbClock lt;= not TbClock after TbPeriod/2 when TbSimEnded /= '1' else '0';

    clk lt;= TbClock;

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

    wait for 50 us; -- Adjust delay to fit the new clock period

    start lt;= '0';

    wait for 400 us; -- Adjust delay to fit the new clock period

    adjustintervalup lt;= '1';

    wait for 20 us; -- Adjust delay to fit the new clock period

    adjustintervalup lt;= '0';

    wait for 50 us; -- Adjust delay to fit the new clock period

    adjustintervaldown lt;= '1';

    wait for 20 us; -- Adjust delay to fit the new clock period

    adjustintervaldown lt;= '0';

    wait for 50 us; -- Adjust delay to fit the new clock period

    - ...

    - Stop the clock and hence terminate the simulation

    TbSimEnded lt;= '1';

    wait;

    end process;

    end tb;

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

    configuration cfgtbKitchenTimer of tbKitchenTimer is

    for tb

    end for;

    end cfgtbKitchenTimer;
    And this is result of simulation:

    • @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).

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

        VHDL code:
        llibrary ieee;
        use ieee.stdlogic1164.all;
        use ieee.numericstd.all;

        entity KitchenTimer is
        port (
        clk : in stdlogic; -- Clock input
        reset : in stdlogic; -- Reset input
        start : in stdlogic; -- Start button input
        stop : in stdlogic; -- Stop button input
        adjustintervalup : in stdlogic; -- Button for increasing alarm interval
        adjustintervaldown : in stdlogic; -- Button for decreasing alarm interval
        alarm : out stdlogic -- Alarm output
        );
        end entity KitchenTimer;
        architecture Behavioral of KitchenTimer is
        signal count : integer range 0 to 3600000 := 0; -- Adjust range for 1 hour
        signal alarming : stdlogic := '0';
        signal alarminterval : integer range 600 to 3600000 := 600; -- Adjust range for 1 hour
        begin
        process (clk, reset)
        begin
        if reset = '1' then
        count lt;= 0;
        alarminterval lt;= 600;
        elsif risingedge(clk) then
        if start = '1' then
        count lt;= count + 1;
        end if;
        if stop = '1' or count = alarminterval then
        count lt;= 0;
        end if;
        if adjustintervalup = '1' then
        if alarminterval lt; 3600000 then
        alarminterval lt;= alarminterval + 600; -- Adjust increment for 1 minute
        end if;
        count lt;= 0; -- Reset count when adjusting interval
        elsif adjustintervaldown = '1' then
        if alarminterval 600 then
        alarminterval lt;= alarminterval - 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 = alarminterval else '0';
        alarm lt;= alarming;
        end architecture Behavioral;

        Testbench:

        library ieee;
        use ieee.stdlogic1164.all;

        entity tbKitchenTimer is
        end tbKitchenTimer;
        architecture tb of tbKitchenTimer is
        component KitchenTimer
        port (
        clk : in stdlogic;
        reset : in stdlogic;
        start : in stdlogic;
        stop : in stdlogic;
        adjustintervalup : in stdlogic;
        adjustintervaldown : in stdlogic;
        alarm : out stdlogic
        );
        end component;
        signal clk : stdlogic := '0';
        signal reset : stdlogic := '0';
        signal start : stdlogic := '0';
        signal stop : stdlogic := '0';
        signal adjustintervalup : stdlogic := '0';
        signal adjustintervaldown : stdlogic := '0';
        signal alarm : stdlogic;
        constant TbPeriod : time := 20 ns;
        signal TbClock : stdlogic := '0';
        signal TbSimEnded : stdlogic := '0';
        begin
        dut : KitchenTimer
        port map (
        clk = clk,
        reset = reset,
        start = start,
        stop = stop,
        adjustintervalup = adjustintervalup,
        adjustintervaldown = adjustintervaldown,
        alarm = alarm
        );
        - Clock generation
        TbClock lt;= not TbClock after TbPeriod/2 when TbSimEnded /= '1' else '0';
        clk lt;= TbClock;
        stimuli : process
        variable numticks : 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
        adjustintervalup lt;= '1';
        wait for 100 us;
        adjustintervalup lt;= '0';
        wait for 100 us;
        adjustintervaldown lt;= '1';
        wait for 100 us;
        adjustintervaldown 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:

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

          KitchenTimer.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;
          
          
            

          tbKitchenTimer.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.

          • @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.stdlogic1164.all;
            use ieee.numericstd.all;
            entity KitchenTimer is
            port (
            clk : in stdlogic; -- Clock input
            reset : in stdlogic; -- Reset input
            start : in stdlogic; -- Start button input
            stop : in stdlogic; -- Stop button input
            adjustintervalup : in stdlogic; -- Button for increasing alarm interval
            adjustintervaldown : in stdlogic; -- Button for decreasing alarm interval
            alarm : out stdlogic -- Alarm output
            );
            end entity KitchenTimer;
            architecture Behavioral of KitchenTimer is
            signal count : integer range 0 to 3600000 := 0; -- Adjust range for 1 hour
            signal alarming : stdlogic := '0';
            signal alarminterval : integer range 600 to 3600000 := 600; -- Adjust range for 1 hour
            begin
            process (clk, reset)
            begin
            if reset = '1' then
            count lt;= 0;
            alarminterval lt;= 600;
            elsif risingedge(clk) then
            if start = '1' then
            count lt;= count + 1;
            end if;
            if stop = '1' or count = alarminterval then
            count lt;= 0;
            end if;
            if adjustintervalup = '1' then
            if alarminterval lt; 3600000 then
            alarminterval lt;= alarminterval + 600; -- Adjust increment for 1 minute
            end if;
            count lt;= 0; -- Reset count when adjusting interval
            elsif adjustintervaldown = '1' then
            if alarminterval 600 then
            alarminterval lt;= alarminterval - 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 = alarminterval else '0';
            alarm lt;= alarming;
            end architecture Behavioral;

            Testbench:

            library ieee;
            use ieee.stdlogic1164.all;
            entity tbKitchenTimer is
            end tbKitchenTimer;
            architecture tb of tbKitchenTimer is
            component KitchenTimer
            port (
            clk : in stdlogic;
            reset : in stdlogic;
            start : in stdlogic;
            stop : in stdlogic;
            adjustintervalup : in stdlogic;
            adjustintervaldown : in stdlogic;
            alarm : out stdlogic
            );
            end component;
            signal clk : stdlogic := '0';
            signal reset : stdlogic := '0';
            signal start : stdlogic := '0';
            signal stop : stdlogic := '0';
            signal adjustintervalup : stdlogic := '0';
            signal adjustintervaldown : stdlogic := '0';
            signal alarm : stdlogic;
            constant TbPeriod : time := 20 ns;
            signal TbClock : stdlogic := '0';
            signal TbSimEnded : stdlogic := '0';
            begin
            dut : KitchenTimer
            port map (
            clk = clk,
            reset = reset,
            start = start,
            stop = stop,
            adjustintervalup = adjustintervalup,
            adjustintervaldown = adjustintervaldown,
            alarm = alarm
            );
            - Clock generation
            TbClock lt;= not TbClock after TbPeriod/2 when TbSimEnded /= '1' else '0';
            clk lt;= TbClock;
            stimuli : process
            variable numticks : 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
            adjustintervalup lt;= '1';
            wait for 100 us;
            adjustintervalup lt;= '0';
            wait for 100 us;
            adjustintervaldown lt;= '1';
            wait for 100 us;
            adjustintervaldown 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;

23 comments