Smoke apparatus 1011 detector in VHDL
I am writing a VHDL program for a Mealy machine that can detect the 1011 pattern like this:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY mealy_detector_1011 IS
PORT(
rst_n : IN STD_LOGIC;
clk : IN STD_LOGIC;
data : IN STD_LOGIC;
result : OUT STD_LOGIC);
END ENTITY;
ARCHITECTURE beh OF mealy_detector_1011 IS
TYPE state IS (IDLE, GOT1, GOT10, GOT101);
SIGNAL current_state : state;
SIGNAL next_state : state;
BEGIN
REG: PROCESS(clk, rst_n)
BEGIN
IF rst_n = '0' THEN
current_state <= IDLE;
ELSIF rising_edge(clk) THEN
current_state <= next_state;
END IF;
END PROCESS REG;
NEXTSTATE: PROCESS(data, current_state)
BEGIN
CASE current_state IS
WHEN IDLE =>
IF data = '1' THEN
next_state <= GOT1;
ELSE next_state <= IDLE;
END IF;
WHEN GOT1 =>
IF data = '0' THEN
next_state <= GOT10;
ELSE next_state <= GOT1;
END IF;
WHEN GOT10 =>
IF data = '1' THEN
next_state <= GOT101;
ELSE next_state <= IDLE;
END IF;
WHEN GOT101 =>
IF data = '1' THEN
next_state <= GOT1;
ELSE
next_state <= GOT10;
END IF;
WHEN OTHERS => NULL;
END CASE;
END PROCESS NEXTSTATE;
result <= '1' WHEN (current_state = GOT101 and data = '1') ELSE '0';
END beh;
and a .do file to simulate the following
vcom mealy_detector_1011.vhd
vsim mealy_detector_1011
add wave -r /*
force -freeze /clk 1 0, 0 50 -r 100
force -freeze /rst_n 0 0, 1 10
force -freeze /data 0 0, 1 80, 0 180, 1 230, 0 330, 1 470, 0 530, 1 570, 0 620
run 800 ns
However, my simulation result is incorrect. Can you help me solve this problem? Thank!
source to share
You keep getting answers from people who seem to perceive the problem with result
.
The problem is that data
it is not in sync with clk
. You have transitions all over the place, the mealy conclusion does exactly what it should do.
This is a combinatorial output and should not be used like a watch. It can be used as a permission or entry for a register running on clk
.
Here's a test bench for those of us who don't have Modelsim:
library ieee;
use ieee.std_logic_1164.all;
entity mealy_1011_tb is
end entity;
architecture foo of mealy_1011_tb is
signal rst_n: std_logic := '0';
signal clk: std_logic := '1';
signal data: std_logic := '0';
signal result: std_logic;
begin
DUT:
entity work.mealy_detector_1011
port map (
rst_n => rst_n,
clk => clk,
data => data,
result => result
);
CLOCK:
process
begin
wait for 50 ns;
clk <= not clk;
if Now > 799 ns then
wait;
end if;
end process;
STIMULUS:
process
begin
wait for 10 ns;
rst_n <= '1';
wait for 70 ns;
data <= '1'; -- 80 ns
wait for 100 ns;
data <= '0'; -- 180 ns
wait for 50 ns;
data <= '1'; -- 230 ns
wait for 100 ns;
data <= '0'; -- 330 ns
wait for 140 ns;
data <= '1'; -- 470 ns
wait for 60 ns;
data <= '0'; -- 530 ns
wait for 40 ns;
data <= '1'; -- 570 ns
wait for 50 ns;
data <= '0'; -- 620 ns
wait;
end process;
end architecture;
And it gives the same answer as your simulation:
You don't want to see an extra drop on result
, do data
sync your watch. Your statemachine does exactly what it should.
And if there data
were synchronous clock cycles, you could shutter result
with clk
with not clk nand result
and create clock of result events.
source to share
You just need to write your Mealy outputs to the if-then-else branch of your process.
NEXTSTATE: PROCESS(data, current_state)
BEGIN
-- default assignments
next_state <= state; -- so your code won't create latches
result <= '0'; -- result is always 0, except of transition GOT101 to GOT1
CASE current_state IS
WHEN IDLE =>
IF data = '1' THEN
next_state <= GOT1;
ELSE next_state <= IDLE;
END IF;
WHEN GOT1 =>
IF data = '0' THEN
next_state <= GOT10;
ELSE next_state <= GOT1;
END IF;
WHEN GOT10 =>
IF data = '1' THEN
next_state <= GOT101;
ELSE next_state <= IDLE;
END IF;
WHEN GOT101 =>
IF data = '1' THEN
result <= '1';
next_state <= GOT1;
ELSE
next_state <= GOT10;
END IF;
WHEN OTHERS => NULL;
END CASE;
END PROCESS NEXTSTATE;
source to share