Example – Process Activation

Широчинно-импулсен Модулатор (PWM)

Илюстрира условията за активиране на процес.


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity pwm is
    generic ( WIDTH : natural);
    port ( clock : in  std_logic;
      reset : in  std_logic;
      duty : in  unsigned (WIDTH-1 downto 0);
      pwm : out std_logic);
end pwm;
 
architecture with_concurrent_assignment of pwm is
    constant CNT_MAX : unsigned(WIDTH-1 downto 0) := (others=>'1');
    constant CNT_MIN : unsigned(WIDTH-1 downto 0) := (others=>'0');
    
    type direction is (UP,DOWN);
    
    signal dir: direction;    
    signal cnt : unsigned(WIDTH-1 downto 0);
begin
    -- 'cnt' and 'duty' are in the 'implicit' sensitivity list 
    -- of the concurrent assignment
    pwm <= '1' when cnt < duty else '0';

    up_down_counter: process(clock, reset) begin
        if( reset = '1') then
            cnt <= (others => '0');
            dir <= UP;
        elsif rising_edge(clock) then
            if( dir = UP ) then
                if( cnt = CNT_MAX ) then
                    dir <= DOWN;
                else
                    cnt <= cnt + 1;
                end if;
            else
                if( cnt = CNT_MIN ) then
                    dir <= UP;
                else
                    cnt <= cnt - 1;
                end if;       
            end if;
        end if;
    end process;  
end with_concurrent_assignment;

architecture with_process of pwm is
    constant CNT_MAX : unsigned(WIDTH-1 downto 0) := (others=>'1');
    constant CNT_MIN : unsigned(WIDTH-1 downto 0) := (others=>'0');
    
    type direction is (UP,DOWN);
    
    signal dir: direction;    
    signal cnt : unsigned(WIDTH-1 downto 0);
begin

    -- Illustrates the importance of the sensitivity list.
    -- Without 'cnt' in list, the model behaves erraticaly. 
    comparator: process(duty)
    begin
        if (cnt < duty) then
            pwm <= '1';
        else
            pwm <= '0';
        end if;
    end process;
   
    up_down_counter: process(clock, reset) begin
        if( reset = '1') then
            cnt <= (others => '0');
            dir <= UP;
        elsif rising_edge(clock) then
            if( dir = UP ) then
                if( cnt = CNT_MAX ) then
                    dir <= DOWN;
                else
                    cnt <= cnt + 1;
                end if;
            else
                if( cnt = CNT_MIN ) then
                    dir <= UP;
                else
                    cnt <= cnt - 1;
                end if;       
            end if;
        end if;
    end process;  
end with_process;

Тест

Обърнете внимание на разликите в резултатите от симулациите. Коя архитектура е сгрешена? Отстранете грешката!

Симулация на архитектура with_concurrent_assignment

pwm_ok

Симулация на архитектура with_process

pwm_fail

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity pwm_test is
end pwm_test;
 
architecture behavior of pwm_test is 
 
    constant CLOCK_PERIOD : time := 10 ns;
    constant WIDTH : natural := 4;   

    signal clock_run : boolean := true;

    signal clock : std_logic;
    signal reset : std_logic;
    signal duty : unsigned(WIDTH-1 downto 0) := (others => '0');
    signal pwm : std_logic;
begin
 
	-- instantiate the unit under test (uut)
    uut: entity work.pwm(with_concurrent_assignment)
    generic map( WIDTH => WIDTH)
    port map (
          clock => clock,
          reset => reset,
          duty => duty,
          pwm => pwm
        );

   -- clock process 
    clock_process: process
    begin
        if clock_run then
            clock <= '0';
            wait for CLOCK_PERIOD/2;
            clock <= '1';
            wait for CLOCK_PERIOD/2;
        else
            wait;
        end if;
    end process;
 
   -- stimulus process
   stim_proc: process
   begin   
        reset <= '1';
        duty <= "0011";        
        wait until falling_edge(clock);
        assert pwm = '0' report "pwm must be '0' after reset";

        reset <= '0';
        wait for CLOCK_PERIOD * 198;   
        
        duty <= "1100";
        wait for CLOCK_PERIOD * 200;  
        
        clock_run <= false;
        wait;
   end process;

end;