This is a problem I regularly bump into - hopefully someone can clarify to me the right way to think about it!
I can basically reduce my problem to this: I have a module, with input p_in
, output p_out
and clock clk
. The functionality is that whenever in
goes low - out
should produce a high pulse with a duration of one clock period; and this "negative edge detector" is implemented as an FSM with four states: reset
; wt_in_lo
(wait for input low); sample_signal
(generate high signal on output, upon detected transition to zero on input); wt_in_hi
(wait for input high, after sample signal has been raised).
The code is included below, and the result in the isim
simulator looks like this (and this is behavioral simulation, so there shouldn't be any platform-specific translation influence):
Basically, the states do change as I expect them to - first clock posedge, the FSM recognizes in
is low, so it transits to sample_signal
; second clock posedge, we are in sample_signal
state.
- However, here is my problem - I'd expect for the
out
to go high as soon as thesample_signal
state is entered (or at least, that's what I'm trying to achieve); yet, theout
doesn't perform the high pulse until the next state (wt_in_hi
) is entered!
And then I usually try to code around this (i.e. setting out
in the synchronous fsm part, which is probably a bad idea) - and end up confusing both the synthesizer and myself :)
So, in brief - is it possible that I get an out
signal as soon as the second state is entered (and for the duration of second state); and what would be the proper way to code it?
Many thanks in advance for any answers,
Cheers!
The code:
-- file: fsm_react_test_twb.vhd
---------------
-- single file testbench examples - see also;
-- http://www.cs.umbc.edu/portal/help/VHDL/samples/samples.shtml
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
-- NEVER call port pins "in"; "out": ERROR:HDLCompiler:806 'Syntax error near "in"'!
ENTITY negedgeDetector IS
PORT (
clk: IN STD_LOGIC;
p_in : IN STD_LOGIC;
p_out: OUT STD_LOGIC
);
END negedgeDetector;
ARCHITECTURE structure OF negedgeDetector IS
-- 'dummy signals' - registers
SIGNAL w_in : STD_LOGIC := 'Z';
SIGNAL w_out : STD_LOGIC := 'Z';
-- fsm states
TYPE states_ned IS -- ned: negedgeDetector
(
ned_reset,
ned_wt_in_lo, -- wait for in active low
ned_sample_signal, -- signal for sampling
ned_wt_in_hi -- wait for in active hi
);
-- init fsm state vars
SIGNAL state_ned, next_state_ned: states_ned := ned_reset;
-- implementation:
BEGIN
-- assign 'wire' / registers
w_in <= p_in;
p_out <= w_out;
-- STATE MACHINES CODE =========
sm_ned: PROCESS(state_ned, w_in) -- combinatorial process part
BEGIN
CASE state_ned IS
WHEN ned_reset =>
next_state_ned <= ned_wt_in_lo;
WHEN ned_wt_in_lo =>
IF w_in = '0' THEN
next_state_ned <= ned_sample_signal;
ELSE
next_state_ned <= ned_wt_in_lo;
END IF;
WHEN ned_sample_signal =>
next_state_ned <= ned_wt_in_hi;
WHEN ned_wt_in_hi =>
IF w_in = '0' THEN
next_state_ned <= ned_wt_in_lo;
ELSE
next_state_ned <= ned_wt_in_hi;
END IF;
END CASE;
END PROCESS sm_ned;
out_sm_ned: PROCESS(clk) -- synchronous process part --
BEGIN
IF (rising_edge(clk)) THEN -- returns only valid transitions;
IF state_ned = ned_sample_signal THEN
-- signal for sampling
w_out <= '1';
ELSE
w_out <= '0';
END IF;
state_ned <= next_state_ned;
END IF;
END PROCESS out_sm_ned;
-- END STATE MACHINES CODE =====
END structure; -- ARCHITECTURE
-- #########################
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
ENTITY fsm_react_test_twb IS
END fsm_react_test_twb;
ARCHITECTURE testbench_arch OF fsm_react_test_twb IS
COMPONENT negedgeDetector
PORT(
clk: IN STD_LOGIC;
p_in : IN STD_LOGIC;
p_out: OUT STD_LOGIC
);
END COMPONENT;
-- 'wires'
SIGNAL wCLK : std_logic := '0';
SIGNAL wIN : std_logic := 'Z';
SIGNAL wOUT : std_logic := 'Z';
-- clock parameters
constant PERIODN : natural := 20; -- can be real := 20.0;
constant PERIOD : time := PERIODN * 1 ns;
constant DUTY_CYCLE : real := 0.5;
constant OFFSET : time := 100 ns;
-- implementation of workbench
BEGIN
-- instances of components, and their wiring (port maps)...
UUT : negedgeDetector -- VHDL
PORT MAP(
clk => wCLK,
p_in => wIN,
p_out => wOUT
);
-- PROCESSES (STATE MACHINES) CODE =========
-- clock process for generating CLK
clocker: PROCESS
BEGIN
WAIT for OFFSET;
CLOCK_LOOP : LOOP
wCLK <= '0';
WAIT FOR (PERIOD - (PERIOD * DUTY_CYCLE));
wCLK <= '1';
WAIT FOR (PERIOD * DUTY_CYCLE);
END LOOP CLOCK_LOOP;
END PROCESS clocker;
simulator: PROCESS
BEGIN
WAIT for OFFSET;
WAIT for 10 ns;
-- take 'in' low - out should detect it with a pulse
wIN <= '0';
WAIT for 50 ns;
-- take 'in' high - no out
wIN <= '1';
WAIT for 50 ns;
-- repeat
wIN <= '0';
WAIT for 50 ns;
wIN <= '1';
WAIT for 50 ns;
-- hold
WAIT;
END PROCESS simulator;
-- END PROCESSES (STATE MACHINES) CODE =====
END testbench_arch; -- ARCHITECTURE
-----------------------
-- call with (Xilinx ISE WebPack 13.2 tools):
-- # note: -tclbatch (isim script) _needs_ -view (*.wcfg) to run! (empty *.wcfg ok)
-- # must use isim script to run at start (and setup view)..
-- # first run:
-- echo 'vhdl work "fsm_react_test_twb.vhd"' > fsm_react_test_twb.prj
-- touch fsm_react_test_twb.wcfg
-- echo -e "wave add {/fsm_react_test_twb/wclk}\nwave add {/fsm_react_test_twb/win}\nwave add {/fsm_react_test_twb/wout}\nwave add {/fsm_react_test_twb/UUT/state_ned}\nwave add {/fsm_react_test_twb/UUT/next_state_ned}\nrun 500 ns\n" > fsm_react_test_twb.isim
-- # build sim and run:
-- fuse -o fsm_react_test_twb.exe -prj fsm_react_test_twb.prj work.fsm_react_test_twb
-- ./fsm_react_test_twb.exe -gui -tclbatch fsm_react_test_twb.isim -view fsm_react_test_twb.wcfg