мой код 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
. Это три процесса, которые поддерживают синхронизацию выходов как с часами, так и с состоянием:
- Государственный регистр и регистр выходов.
- Логика следующего состояния.
- Далее логика выходов.
Я также добавил несколько 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