Why does this FSM not reach 100% code coverage? - vhdl

I have the following simple FSM description in VHDL:
library ieee;
use ieee.std_logic_1164.all;
entity coverage1 is
port (
clk : in std_logic;
rst : in std_logic;
req : in std_logic;
ack : out std_logic
);
end entity coverage1;
architecture rtl of coverage1 is
type STATES is (IDLE, RUNNING, FINISH);
signal fsm_cs : STATES := IDLE;
signal fsm_ns : STATES;
begin
process (fsm_cs, req) is
begin
fsm_ns <= fsm_cs;
ack <= '0';
case fsm_cs is
when IDLE =>
if req = '1' then
fsm_ns <= RUNNING;
end if;
when RUNNING =>
fsm_ns <= FINISH;
when FINISH =>
ack <= '1';
fsm_ns <= IDLE;
when others =>
null;
end case;
end process;
process (clk) is
begin
if rising_edge(clk) then
if rst = '1' then
fsm_cs <= IDLE;
else
fsm_cs <= fsm_ns;
end if;
end if;
end process;
end architecture;
And this testbench:
library ieee;
use ieee.std_logic_1164.all;
entity coverage1_tb is
end entity coverage1_tb;
architecture tb of coverage1_tb is
signal clk : std_logic := '1';
signal rst : std_logic;
signal req : std_logic;
signal ack : std_logic;
signal finished : boolean := false;
begin
coverage1_1: entity work.coverage1
port map (
clk => clk,
rst => rst,
req => req,
rdy => rdy,
ack => ack);
clk <= not clk after 5 ns when not finished else unaffected;
process
begin
rst <= '1';
wait until rising_edge(clk);
rst <= '0';
req <= '0';
wait until rising_edge(clk);
req <= '1';
wait until rising_edge(clk);
req <= '0';
wait until rising_edge(clk) and ack = '1';
wait until rising_edge(clk);
finished <= true;
wait;
end process;
end architecture tb;
The FSM does not reach 100% code coverage in ModelSim/QuestaSim. I found two issues:
The others case, which is not required because the enumeration is fully covered by all choices, is requested to be covered. But this branch is not reachable... Why does QuestaSim expect coverage for this branch?
QuestaSim shows a false state diagram for my example FSM. The diagram contains self-edges for the states: RUNNING and FINISH. These edges do not exist nor can they be covered.
If I remove the default assignment fsm_ns <= fsm_cs; and add an else branch in the IDLE state, I'll get full coverage.
if req = '1' then
fsm_ns <= RUNNING;
else
fsm_ns <= IDLE;
end if;
Why does the state diagram show false edges and why can't I use default assignments?
I could live with bullet item 1, but item 2 is a problem. If I write my FSMs in that style, I'm duplicating a lot of unneeded code and most synthesizers won't recognize the FSM pattern! So I'll lose FSM optimizations and checking in synthesis.

Some observations, again using ghdl.
Commenting out the rdy port, ghdl again reports 100% coverage.
Ironically the null in "others" clause gets 20 hits ... which is suspicious. As it's the last active line in the process I believe any events that wake the process but don't do anything are recorded here.
A null; added after end case collects these 20 hits, confirming this - but the others case still isn't recorded as a coverage hole (despite having no hits). My hypothesis is that because null generates no code it isn't being tracked. Adding a harmless but trackable action fsm_ns <= IDLE; to the when others branch now gives a coverage hole (which, annoyingly, receives spurious hits when the null after end case is removed.
Summary :
it's worth testing the effect of an active statement as a hook for tracking coverage in when others, and a null after end case so that "end of process" code isn't incorrectly logged on the last case arm
ghdl needs some tidying up in these two areas, perhaps translating null as a 'nop' to hook the coverage to.
Sorry I can't shed light on Modelsim's behaviour here.
However, code that is present but not reachable - "dead code" - is seen as representing a design error in high integrity practices, so I regard Modelsim as correct to highlight it, and ghdl as incorrect in cases where it does not.
It's somewhat related to the issue of safe state machine design where an SEU (perhaps from a cosmic ray) corrupts the state register. Note that with less than 2**n members of STATES, there WILL be an "other" state, and with a null action, this SM will lock up there if it ever reaches that state. (However, deleting the "others" clause won't correct that, and a synthesis tool may conclude the "others" clause is unreachable and delete it anyway. Safe SM design is another topic)

The when others is shown as not covered, as expected. You can exclude it with:
-- coverage off
when others => null;
-- coverage on
I do this in every case statement where the others case can't be
hit.
I get 100% state coverage, even without the else branch. The if conditional in IDLE state has 100% branch coverage, even without an else branch (Active: 4, True Hits: 1, AllFalse: 3). For 100% FSM coverage you should exclude the implicit changes by the reset signal, or you have to pull the reset in every FSM state. You can exclude the reset state changes with -nofsmresettrans swith when compiling.
I get the same behaviour using Modelsim DE 10.5c and 10.6 and Questa 10.6.
BTW: I can't get FSM coverage if parts of the FSM are inside a generate block which depends on a generic, so I had to outcomment the generate stuff and only leave in one of the reset processes. I think this is an Modelsim/Questa limitation that it don't recognizes FSMs inside of generate blocks, but I'm not. The help also hints that FSMs using generics aren't regognized. Maybe that's the case here.

Related

VHDL - Register for Push Button

I'm trying to create a simple push button in VHDL that turns on after an input switch or pb goes from 0 to 1 to 0 using a clock and a process. However, my code seems to be giving me undefined output. Here's what I have so far.
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
Entity captureInput is port
(
CLK : in std_logic := '0';
RESET_n : in std_logic := '0';
buttonState : in std_logic := '0';
buttonOut : out std_logic := '0'
);
end Entity;
ARCHITECTURE one of captureInput is
signal lastButtonState: std_logic := '0';
signal btnState : std_logic := '0';
BEGIN
process (CLK, RESET_n) is
begin
if (RESET_n = '0') then
lastButtonState <= '0';
elsif (rising_edge(CLK)) then
if (buttonState ='0' and lastButtonState = '1') then
btnState <= '1';
end if;
lastButtonState <= buttonState;
end if;
end process;
buttonOut <= btnState
end;
Try to initialize your btnState in the reset branch of your register and also have an else statement where you set your btnState back to 0, under some condition. I would bet that your undefined output comes from the fact that you do not define your btnState anywhere else outside your if conditions. It's good practice to not rely on the initial value of your declaration: Synthesis tools ignore it and some simulators will as well. Also, remember that the clocked body of the if will generate a register for every signal that gets assigned a value inside it, and that signals will keep the last value assigned to them inside a process.
You are also missing the Library ieee; statement at the top and a semicolon after buttonOut <= btnState.
Reading a button do need a debouncer.
Please take a look at:
VHDLWhiz generate statement
or
VHDLWhiz How to read a button in VHDL
Even though I see that you have already accepted Dimitris' answer, I can add that your code is almost right, you just need to toggle on the falling edge of of the latch instead of setting it to '1' as you do.
Try
if(rising_edge(CLK)) then
lastButtonState <= buttonState;
if(buttonState='0' and lastButtonState='1') then
btnState <= not btnState;
end if;
end if;
buttonOut <= btnState -- etc...
You don't need to initialize anything to '0' but you DEFINITELY need a switch debouncer as lukipedio said otherwise your toggle will not be consistent.
If you think about it, what you're doing is putting a "clock divider" on your lastButtonState register by toggling in order to set the btnState register at half the "frequency" of lastButtonState, which is what you want.
BTW, if you switch your toggling condition to
(buttonState='1' and lastButtonState='0')
then it will toggle on the rising edge of lastButtonState, in other words it will be toggle-on-press instead of toggle-on-release.

VHDL: Assigning one std_logic_vector to another makes '1' turn to 'X'

I have a baffling problem.. As part of a buffering process I am assigning one std_logic_vector to another, by simply doing:
dataRegister <= dataRegisterBuf;
The process is synced to a clock. See here for the full process:
--! This process buffers the data register synced to sclk when state is state_bufferingToSclk and sets registerReady when done
SclkDomainBuffering: process(sclk)
variable step: natural := 0;
begin
if (rising_edge(sclk)) then
if (state = state_bufferingToSclk) then
if (step = 0) then
dataRegister <= dataRegisterBuf;
step := 1;
elsif (step = 1) then
registerReady <= '1';
step := 2;
end if;
else
step := 0;
registerReady <= '0';
end if;
end if;
end process SclkDomainBuffering;
The problem is, when simulating this in Modelsim, dataRegister does not take the value of dataRegisterBuf, instead every '1' in the vector becomes 'X'. So for example if dataRegisterBuf is "00010", dataRegister becomes "000X0". I can't for the life of me figure out why. Here is a simulation showing it happening: http://i.imgur.com/znFgqKl.png
I have stepped through the entire code and I can't see anything out of the ordinary. At the time it happens, line 84 in the code above does indeed execute, and that is the only statement that is executed that has anything to do with the two registers in question as far as I can tell.
Here's a Minimal Complete and Verifiable example created from your question and comments:
library ieee;
use ieee.std_logic_1164.all;
entity baffling_problem is
end entity;
architecture foo of baffling_problem is
type state_type is (state_bufferingToClk, state_bufferingToSclk);
signal state: state_type; -- defaults to 'LEFT, state_bufferingToClk
signal dataRegisterBuf: std_logic_vector (31 downto 0) :=
(1 | 2 => '1', others => '0');
signal dataRegister: std_logic_vector (31 downto 0) := (others => '0');
signal registerReady: std_logic;
signal sclk: std_logic := '1';
begin
SclkDomainBuffering: process(sclk)
variable step: natural := 0;
begin
if (rising_edge(sclk)) then
if (state = state_bufferingToSclk) then
if (step = 0) then
dataRegister <= dataRegisterBuf;
step := 1;
elsif (step = 1) then
registerReady <= '1';
step := 2;
end if;
else
step := 0;
registerReady <= '0';
end if;
end if;
end process SclkDomainBuffering;
SOMEOTHERPROCESS:
process (state)
begin
if state = state_type'LEFT then -- other than state_bufferingToSclk
dataRegister <= (others => '0');
end if;
end process;
STIMULI:
process
begin
wait for 20 ns;
sclk <= '0';
wait for 5 ns;
sclk <= '1';
wait for 0 ns; -- state transitions in distinct delta cycle
state <= state_bufferingToSclk;
wait for 20 ns;
sclk <= '0';
wait for 5 ns;
sclk <= '1';
wait for 20 ns;
wait;
end process;
end architecture;
And this gives the behavior your describe:
See IEEE Std 1076-2008 14.7.3 Propagation of signal values, 14.7.3.1 General:
As simulation time advances, the transactions in the projected output waveform of a given driver (see 14.7.2) will each, in succession, become the value of the driver. When a driver acquires a new value in this way or as a result of a force or deposit scheduled for the driver, regardless of whether the new value is different from the previous value, that driver is said to be active during that simulation cycle. For the purposes of defining driver activity, a driver acquiring a value from a null transaction is assumed to have acquired a new value. A signal is said to be active during a given simulation cycle if
— One of its sources is active.
— One of its subelements is active.
— The signal is named in the formal part of an association element in a port association list and the corresponding actual is active.
— The signal is a subelement of a resolved signal and the resolved signal is active.
— A force, a deposit, or a release is scheduled for the signal.
— The signal is a subelement of another signal for which a force or a deposit is scheduled.
So the signals (dataReady(1) and dataReady(2) are active their sources is active.
An explanation of why their values are the resolved value of their drivers is found in 14.7.3.2 Driving values, none of the signals comprising dataReady are basic signals, see paragraph 3 f).
And why you see the value of dataReady as "00000000000000000000000000000XX0" is described in 14.7.3.3 Effective values.
The VHDL language describes how an elaborated design model is simulated as well as describing the syntax and semantics. An elaborated design model consists of processes described in a hierarchy interconnected by signals, and signals have history not just value. Signal updates are scheduled in projected output waveforms (see 10.5 Signal assignment statement).
A lot of users just starting out in VHDL apply what they know of the behavior of other languages to VHDL, an example is the superfluous (but not forbidden) parentheses surrounding a condition in an if statement. Knowledge of other languages doesn't address signal behaviors (determined by the architecture of simulation models driven by simulation cycles.
One of the things you'll note is that processes (11.3) suspend and resume based on explicit or implicit wait statements (10.2).
All concurrent statements are elaborated into processes and or processes and block statements (11. Concurrent statements).
Subprogram calls are either expressions (functions, 9.3.4) or statements (procedures, 10.7).
No signal value is updated while any process that is scheduled to be active (those projected output waveforms matching the current simulation time, 14.7.4 Model execution, 14.7.3.4 Signal update).
Signals driven in multiple processes represent multiple collections of hardware. The problem shows up because you've used resolved data types, if you had used unresolved data types you would have gotten an elaboration error instead (6.4.2.3 Signal declarations, paragraph 8). Resolved signals are allowed to have multiple drivers.
The resolution table for std_logic elements is found in the package body for package std_logic_1164(See footnote 15 Annex A Description of accompanying files for access to the source of VHDL packages included with the standard). The resolution table will resolve a '0' and a '1' to an 'X'.
And if all this sounds complex you can learn simple rules of thumb to prevent problems.
In this case a rule of thumb would be to always drive a signal from a single process.
As people in the comments said, the problem was that another process was driving the same data register. I did not understand that even though that other process only changed the value of the register in a different state, it would still drive the signal during every other state. I fixed the problem by moving everything related to that register into a single process.

Issue formatting "if" statement within testbench process?

This has been driving me crazy. Here’s the code I have so far:
signal SYS_CLK : std_logic := '0'; --Input
signal InputSignal : std_logic := '0'; --Input
signal SyncOutputSignal : std_logic; --Output
------------------------------------------------------
stim_proc:process(SYS_CLK)
begin
if (rising_edge(SYS_CLK)) then
if (InputSignal = '1') then
assert (SyncOutputSignal = '0') report "Bad Pulse..." severity ERROR;
end if;
end if;
end process stim_proc;
And a picture of the ISim waveform ---> i.imgur.com/G5KvCQe.jpg
The purpose of this test is to confirm that when on rising_edge(SYS_CLK) if InputSignal = '1', then a pulse is emitted (SyncOutputSignal) equivalent and in line to SYS_CLK's period.
However, an Error report is being issued everytime the CLK goes high and InputSignal is High.
Long story short, I need a way to tell the program to wait for the next InputSignal Pulse before testing the assert statement listed in my code again. Any ideas??
It sounds like you are trying to check for an edge condition on InputSignal. When checking for an edge condition in hardware, there's a simple thing you can do. Create a registered version of InputSignal (I called it Reg_InputSignal). Then change your if statement to check for a 1 on InputSignal and a 0 on Reg_InputSignal. This is a rising edge condition on InputSignal and should only trip the if statement for 1 clock cycle.
architecture RTL of Entity_Name is
signal Reg_InputSignal : std_logic := '0';
begin
stim_proc : process(SYS_CLK)
begin
if (rising_edge(SYS_CLK)) then
Reg_InputSignal <= InputSignal;
if (InputSignal = '1' and Reg_InputSignal = '0') then
assert (SyncOutputSignal = '0') report "Bad Pulse..." severity error;
end if;
end if;
end process stim_proc;

VHDL Pullup Resisters

I am fairly new to vhdl, I am working to understand if I can use it for a project.
I created a project to see how to implement pullup resisters and see how they work. I must have done something wrong.
My constraints entry for the wire is
net "rx_i" PULLUP;
net "rx_i" loc="p88";
the process for the project is
Process (clk_i)
type state_type is (qInit, qZero, qZero1, qZero2, qZero3, qZero4);
variable state: state_type:= qInit;
Begin
if (rising_edge(clk_i)) then
case state is
when qInit =>
if (rx_i = '0') then
led_o(0) <= '1';
state := qZero;
end if;
when qZero =>
if (rx_i = '0') then
led_o(1) <= '1';
state := qZero1;
end if;
when qZero1 =>
if (rx_i = '0') then
led_o(2) <= '1';
state := qZero2;
end if;
when qZero2 =>
if (rx_i = '0') then
led_o(3) <= '1';
state := qZero3;
end if;
when qZero3 =>
if (rx_i = '0') then
led_o(4) <= '1';
state := qZero4;
end if;
when qZero4 =>
if (rx_i = '0') then
led_o(5) <= '1';
state := qInit;
end if;
end case;
end if;
End Process;
All of the led's 0 thru 5 light up. If the wire is pulled up high I would expect maybe a few spurious 0's but not 6 in a row. Any help would be appreciated.
First: you never set the value of your leds back to '0'. Once you have set all values to '1' in this state machine, you keep driving '1'. You could add a line like led_o <= (others => '0'); before your case statement.
Even then, you will be running through the states at the speed of your clock. Your leds will be blinking so fast that your eyes just sees them as "on", but slightly less bright. perhaps you can add a counter in each state, or check for another condition like a button pushed.
Finally, the code you have posted shows nothing of a pull-up. I'm just assuming you are using that in another part of your code. The problems I can see have nothing to do with pull-ups.
Your constraints file is only used when the code gets synthesized and turned into a bitstream to be loaded onto the FPGA. It has nothing to do with simulation. In simulation you can create a pullup by driving 'H' (high) onto a signal.
If you want led_o to be the signal pulled up you could do:
led_o <= 'H';
led_o <= LED_DRIVE;
So when LED_DRIVE is high impedance (Z) then the pullup will take over and pull the signal high. This is how you would implement a bidirectional interface such as I2C. But I think now that I've gone over your head. The tutorial here shows how you could create a simple LED blinker: http://www.nandland.com/vhdl/tutorials/tutorial-your-first-vhdl-program-part1.html

Can't infer register for ... at ... because it does not hold its value outside the clock edge

This must be the most common problem among people new to VHDL, but I don't see what I'm doing wrong here! This seems to conform to all of the idioms that I've seen on proper state machine design. I'm compiling in Altera Quartus 9.2, for what it's worth. The actual error is:
"Can't infer register for "spiclk_out" at [file] [line] because it does not hold its value outside the clock edge"
ENTITY spi_state_machine IS
PORT(
spiclk_internal : IN STD_LOGIC;
reset : IN STD_LOGIC;
spiclk_out : BUFFER STD_LOGIC
);
END spi_state_machine;
PROCESS(spiclk_internal, reset)
BEGIN
IF reset = '1' THEN
spiclk_out <= '0';
END IF;
IF spiclk_internal = '1' AND spiclk_internal'EVENT THEN --error here
spiclk_out <= NOT spiclk_out;
END IF;
END PROCESS;
Thanks for your time.
As written, the process would cause spiclk_out to toggle on spiclk_internal edges even when reset is active, which is not how flip-flops with asynchronous resets should behave.
What you probably want is
SPICLK: process(spiclk_internal, reset)
if reset = '1' then
spiclk_out <= '0';
elsif spiclk_internal'event and spiclk_internal='1' then
spiclk_out <= not spiclk_out;
end if;
end process SPICLK;

Resources