мой код vhdl для реализации некоторых fsm работает некорректно

library IEEE;
use IEEE.std_logic_1164.all;

entity INCUBATOR2 is
    port(temperature: in std_logic_vector(7 downto 0);
    CLK,RESET: in std_logic;
    on_cooler,on_heater: out std_logic;
    CRS:out std_logic_vector(3 downto 0));

end entity INCUBATOR2;

architecture ARCH of INCUBATOR2 is



TYPE STATE_TYPE_left IS (S1, S2, S3);
SIGNAL STATE,NEXT_STATE   : STATE_TYPE_left;

TYPE STATE_TYPE_right IS (S_OUT,S_1, S_2, S_3);
SIGNAL cooler_STATE,cooler_NEXT_STATE   : STATE_TYPE_right;


begin
    --T<= temprature;
    REG: process (clk, reset) begin
        if reset='1' then
            STATE <= S1 ;
            cooler_STATE<=S_OUT;
        elsif clk'event and clk='1' then
            STATE <= NEXT_STATE ;
            cooler_STATE<=cooler_NEXT_STATE;
        end if ;    
    end process REG ;
   
    CMB:process(STATE,temperature   ,cooler_STATE) 
    begin
        case STATE is
            when S1 => 
                if(temperature  > "00100011" ) then
                    NEXT_STATE<=S2;
                    
                elsif(temperature < "00001111") then
                    NEXT_STATE<= S3;
                end if;
                --cooler_NEXT_STATE<=S_OUT;
            when S2 =>
                if(temperature < "00011001" ) then
                    NEXT_STATE<=S1;
                end if;
                case cooler_STATE is
                    when S_OUT=>
                        if(temperature>"00100011") then
                            cooler_NEXT_STATE<=S_1;
                        end if;
                    when S_1=>
                        if(temperature>"00101000") then
                            cooler_NEXT_STATE<=S_2;
                        elsif(temperature<"00011001") then
                            cooler_NEXT_STATE<=S_OUT;
                        end if;
                    when S_2=>
                        if(temperature>"00101101") then
                            cooler_NEXT_STATE<=S_3;
                        elsif(temperature<"00100011") then
                            cooler_NEXT_STATE<=S_1;
                        end if;
                    when S_3=>
                        if(temperature<"00101000") then
                            cooler_NEXT_STATE<=S_2;
                        end if;
                end case;
                

                
            when S3 => 
                if(temperature>"00011110" ) then
                    NEXT_STATE<=S1;
                end if;
                --cooler_NEXT_STATE<=S_OUT;
        end case;
        
    end process CMB;
  --  with STATE select
--  heater<= '0' when S1|S2,
--      '1' when S3;
--  cooler<= '0' when S1|S3,
--      '1' when S2;
  --  label if( cooler='1') generate
    --  modul: COOLER port  map(temprature=>T,CRS=>CRS,clk=>clk,reset=>reset);
     --end generate;
    
    OUTPUT : process(STATE,cooler_STATE) 
    begin
            
        case STATE is
            when S1 =>
                on_heater<='0';
                on_cooler<='0';
                
            when S2 =>
                on_cooler<='1';
                on_heater<='0';

                
                case cooler_STATE is
                    when S_OUT =>
                        CRS<="0000";
                    when S_1 =>
                        CRS<="0100";
                    when S_2 =>
                        CRS<="0110";
                    when S_3 =>
                        CRS<="1000";
                    when others=>
                        CRS<="0000";
                end case;
                
            when S3 =>
                on_heater<='1';
                on_cooler<='0';

        end case;
        
    end process OUTPUT;

    
end ARCH;

и вот тестовый стенд:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;

entity incubator_tb is
end entity;

architecture testbench of incubator_tb is

component INCUBATOR2 is
    port(temperature: in std_logic_vector(7 downto 0);
    CLK,RESET: in std_logic;
    on_cooler,on_heater: out std_logic;
    CRS:out std_logic_vector(3 downto 0));
end component INCUBATOR2;

signal  CLK, reset: std_logic;
signal  on_cooler,on_heater:std_logic;
signal temperature:std_logic_vector(7 downto 0);
signal CRS: std_logic_vector(3 downto 0);
begin

modul: INCUBATOR2 port map(
temperature => temperature, clk => clk, reset => reset,
on_cooler => on_cooler,on_heater=>on_heater,CRS=>CRS);

stim: process
begin

temperature <= "00100110";
clk <= '0';
reset <= '1';
wait for 20 ns;

temperature <= "00100110";
clk <= '1';
reset <= '0';

wait for 20 ns;

reset <= '0';
clk <= '0';
temperature <= "00001010";
wait for 20 ns;

reset <= '0';
clk <= '1';
temperature <= "00001010";
wait for 20 ns;

reset <= '0';
clk <= '0';
temperature <= "00100110";
wait for 20 ns;
--clk <= '1';

reset <= '0';
clk <= '1';
temperature <= "00100110";
wait for 20 ns;

reset <= '0';
clk <= '1';
temperature <= "00101010";
wait for 20 ns;


wait;

end process;
end architecture testbench;

как показано на рисунке ниже, выходы некоторых входов вычисляются неправильно, и on_heater никогда не активируется...(предполагается, что он переключится на 1, когда температура равна a)

Может ли кто-нибудь сказать мне, что где я делаю неправильно? Я так запутался, любая помощь будет очень признательна.

1 ответ

Поскольку вы должны спроектировать только правый конечный автомат (кулер), вам следует сосредоточиться на нем, отдельном от левого конечного автомата (главного контроллера).

Поговорите со своим коллегой, который разрабатывает главный контроллер, чтобы добавить выход под названием enable_coolerчтобы включить машину состояний кулера. ВIncubator объект может включать два объекта, называемых MainController а также Cooler.

Я выделил логику более крутого конечного автомата в отдельный объект, названный Cooler. Это три процесса, которые поддерживают синхронизацию выходов как с часами, так и с состоянием:

  1. Государственный регистр и регистр выходов.
  2. Логика следующего состояния.
  3. Далее логика выходов.

Я также добавил несколько else предложения, чтобы предотвратить предполагаемые защелки, и добавили некоторые константы, чтобы сделать его более читаемым и поддерживаемым.

Конечный автомат кулера

Диаграмма состояния

Рисунок 1 - Конечный автомат кулера


VHDL

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

entity Cooler is
    port
    (
        clock: in std_logic;
        reset: in std_logic;
        enable: in std_logic;  -- ADDED: From cooler enable signal of modified left-hand state machine.
        temperature: in std_logic_vector(7 downto 0);  -- I've assumed this is a signed temperature.
        crs: out std_logic_vector(3 downto 0)
    );
end entity;

architecture V1 of Cooler is

    type TState is (S_OUT, S_1, S_2, S_3);
    signal state, next_state: TState;

    signal next_crs: std_logic_vector(3 downto 0);  -- ADDED to ensure the outputs are synchronised to the clock and state.

    constant TEMPERATURE_P25: integer := 25;  -- ADDED for readability and maintainability.
    constant TEMPERATURE_P35: integer := 35;
    constant TEMPERATURE_P40: integer := 40;
    constant TEMPERATURE_P45: integer := 45;

    constant RPS_0: std_logic_vector(3 downto 0) := "0000";  -- ADDED for readability and maintainability.
    constant RPS_4: std_logic_vector(3 downto 0) := "0100";
    constant RPS_6: std_logic_vector(3 downto 0) := "0110";
    constant RPS_8: std_logic_vector(3 downto 0) := "1000";

begin

    --
    -- State Register and Outputs Register
    --
    process(clock, reset)
    begin
        if reset then
            state <= S_OUT;
            crs <= RPS_0;  -- ADDED to specify outputs for reset condition.
        elsif rising_edge(clock) then
            state <= next_state;  -- State is synchronised to clock.
            crs <= next_crs;      -- Outputs are synchronised to clock and state.
        end if;
    end process;

    --
    -- Next State Logic
    --
    process(enable, state, temperature)
        variable i_temperature: integer;  -- ADDED for numeric comparisons.
    begin
        if enable then
            i_temperature := to_integer(signed(temperature));  -- I've assumed this is a signed temperature.
            case state is
                when S_OUT =>
                    if i_temperature > TEMPERATURE_P35 then
                        next_state <= S_1;
                    else
                        next_state <= S_OUT;  -- ADDED to prevent inferred latch.
                    end if;
                when S_1 =>
                    if i_temperature > TEMPERATURE_P40 then
                        next_state <= S_2;
                    elsif i_temperature < TEMPERATURE_P25 then
                        next_state <= S_OUT;
                    else
                        next_state <= S_1;  -- ADDED to prevent inferred latch.
                    end if;
                when S_2 =>
                    if i_temperature > TEMPERATURE_P45 then
                        next_state <= S_3;
                    elsif i_temperature < TEMPERATURE_P35 then
                        next_state <= S_1;
                    else
                        next_state <= S_2;  -- ADDED to prevent inferred latch.
                    end if;
                when S_3 =>
                    if i_temperature < TEMPERATURE_P40 then
                        next_state <= S_2;
                    else
                        next_state <= S_3;  -- ADDED to prevent inferred latch.
                    end if;
                when others =>
                    next_state <= S_OUT;
            end case;
        else
            next_state <= S_OUT;  -- Prevent inferred latch.
        end if;
    end process;

    --
    -- Next Outputs Logic
    --
    process(next_state)
    begin
        case next_state is
            when S_OUT =>
                next_crs <= RPS_0;
            when S_1 =>
                next_crs <= RPS_4;
            when S_2 =>
                next_crs <= RPS_6;
            when S_3 =>
                next_crs <= RPS_8;
            when others =>
                next_crs <= RPS_0;
        end case;
    end process;

end architecture;

Конечный автомат главного контроллера

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

entity MainController is
    port
    (
        clock: in std_logic;
        reset: in std_logic;
        temperature: in std_logic_vector(7 downto 0);
        on_cooler: out std_logic;
        on_heater: out std_logic;
        enable_cooler: out std_logic  -- ADDED to enable cooler when MainController is in state S2.
    );
end entity;

architecture V1 of MainController is

    type TState is (S1, S2, S3);
    signal state, next_state: TState;

    constant TEMPERATURE_P15: integer := 15;  -- ADDED for readability and maintainability.
    constant TEMPERATURE_P25: integer := 25;
    constant TEMPERATURE_P30: integer := 30;
    constant TEMPERATURE_P35: integer := 35;

    signal next_on_cooler: std_logic;  -- ADDED to ensure outputs are synchronised to the clock and state.
    signal next_on_heater: std_logic;

begin

    --
    -- State Register and Outputs Register
    --
    process(clock, reset)
    begin
        if reset then
            state <= S1;
            on_cooler <= '0';  -- ADDED to specify outputs for reset condition.
            on_heater <= '0';
        elsif rising_edge(clock) then
            state <= next_state;          -- State is synchronised to the clock.
            on_cooler <= next_on_cooler;  -- Outputs are synchronised to the clock and state.
            on_heater <= next_on_heater;
        end if;
    end process;

    --
    -- Next State Logic
    --
    process(state, temperature)
        variable i_temperature: integer;  -- ADDED for numeric comparisons.
    begin
        i_temperature := to_integer(signed(temperature));  -- I've assumed this is a signed temperature.
        case STATE is
            when S1 =>
                if i_temperature > TEMPERATURE_P35 then
                    next_state <= S2;
                elsif i_temperature < TEMPERATURE_P15 then
                    next_state <= S3;
                else
                    next_state <= S1;  -- ADDED to prevent inferred latch.
                end if;
            when S2 =>
                if i_temperature < TEMPERATURE_P25 then
                    next_state <= S1;
                else
                    next_state <= S2;  -- ADDED to prevent inferred latch.
                end if;
            when S3 =>
                if i_temperature > TEMPERATURE_P30 then
                    next_state <= S1;
                else
                    next_state <= S3;  -- ADDED to prevent inferred latch.
                end if;
            when others =>
                next_state <= S1;
        end case;
    end process;

    --
    -- Next Outputs Logic
    --
    process(next_state)
    begin
        case next_state is
            when S1 =>
                next_on_cooler <= '0';
                next_on_heater <= '0';
                enable_cooler <= '0';
            when S2 =>
                next_on_cooler <= '1';
                next_on_heater <= '0';
                enable_cooler <= '1';  -- ADDED to enable cooler when MainController is in state S2.
            when S3 =>
                next_on_cooler <= '0';
                next_on_heater <= '1';
                enable_cooler <= '0';
            when others =>
                next_on_cooler <= '0';
                next_on_heater <= '0';
                enable_cooler <= '0';
        end case;
    end process;

end architecture;

Инкубатор высшего уровня

Это соединяет два конечных автомата вместе, т.е. Cooler а также MainController.

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

entity Incubator is
    port
    (
        clock: in std_logic;
        reset: in std_logic;
        temperature: in std_logic_vector(7 downto 0);
        on_cooler: out std_logic;
        on_heater: out std_logic;
        crs: out std_logic_vector(3 downto 0)
    );
end entity;

architecture V1 of Incubator is

    signal enable_cooler: std_logic;  -- ADDED to enable cooler when MainController is in state S2.

    component MainController is
        port
        (
            clock: in std_logic;
            reset: in std_logic;
            temperature: in std_logic_vector(7 downto 0);
            on_cooler: out std_logic;
            on_heater: out std_logic;
            enable_cooler: out std_logic
        );
    end component;

    component Cooler is
        port
        (
            clock: in std_logic;
            reset: in std_logic;
            enable: in std_logic;  -- ADDED: From cooler enable signal of modified left-hand state machine.
            temperature: in std_logic_vector(7 downto 0);  -- I've assumed this is a signed temperature.
            crs: out std_logic_vector(3 downto 0)
        );
    end component;

begin

    MC: MainController
        port map
        (
            clock => clock,
            reset => reset,
            temperature => temperature,
            on_cooler => on_cooler,
            on_heater => on_heater,
            enable_cooler => enable_cooler
        );

    CLR: Cooler
        port map
        (
            clock => clock,
            reset => reset,
            enable => enable_cooler,
            temperature => temperature,
            crs => crs
        );

end architecture;

Испытательный стенд

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

entity Incubator_TB is
end entity;

architecture V1 of Incubator_TB is

    constant CLOCK_PERIOD: time := 50 ns;

    signal halt_sys_clock: boolean := false;

    signal clock: std_logic := '0';
    signal reset: std_logic := '0';
    signal temperature: std_logic_vector(7 downto 0);
    signal on_cooler: std_logic;
    signal on_heater: std_logic;
    signal crs: std_logic_vector(3 downto 0);

    component Incubator is
        port
        (
            clock: in std_logic;
            reset: in std_logic;
            temperature: in std_logic_vector(7 downto 0);
            on_cooler: out std_logic;
            on_heater: out std_logic;
            crs: out std_logic_vector(3 downto 0)
        );
    end component;

begin

    ClockGenerator:
    process
    begin
        while not halt_sys_clock loop
            wait for CLOCK_PERIOD / 2.0;
            clock <= not clock;
        end loop;
        wait;
    end process ClockGenerator;

    Stimulus:
    process
    begin
        reset <= '0';
        temperature <= std_logic_vector(to_unsigned(38, temperature'length));
        wait for CLOCK_PERIOD / 4.0;
        reset <= '1';
        wait for CLOCK_PERIOD;
        reset <= '0';
        wait for CLOCK_PERIOD * 4;
        temperature <= std_logic_vector(to_unsigned(12, temperature'length));
        wait for CLOCK_PERIOD * 4;
        temperature <= std_logic_vector(to_unsigned(38, temperature'length));
        wait for CLOCK_PERIOD * 4;
        temperature <= std_logic_vector(to_unsigned(43, temperature'length));
        wait for CLOCK_PERIOD * 4;
        temperature <= std_logic_vector(to_unsigned(48, temperature'length));
        wait for CLOCK_PERIOD * 4;
        temperature <= std_logic_vector(to_unsigned(10, temperature'length));
        wait for CLOCK_PERIOD * 4;
        halt_sys_clock <= true;
        wait;
    end process;
    
    INC: Incubator
        port map
        (
            clock => clock,
            reset => reset,
            temperature => temperature,
            on_cooler => on_cooler,
            on_heater => on_heater,
            crs => crs
        );

end architecture;

Моделирование

Рисунок 2 - Моделирование инкубатора


Схема Quartus RTL

Рисунок 3 - Инкубатор RTL


Рисунок 4 - Главный контроллер RTL


Рисунок 5 - Кулер RTL


Другие вопросы по тегам